From f946163e8818bca1bd9f07636c17ac5400a05d46 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 18 Apr 2018 18:30:45 +0300 Subject: [PATCH 01/47] rendezvous protobuf --- pb/rendezvous.pb.go | 324 ++++++++++++++++++++++++++++++++++++++++++++ pb/rendezvous.proto | 56 ++++++++ 2 files changed, 380 insertions(+) create mode 100644 pb/rendezvous.pb.go create mode 100644 pb/rendezvous.proto diff --git a/pb/rendezvous.pb.go b/pb/rendezvous.pb.go new file mode 100644 index 0000000..6396912 --- /dev/null +++ b/pb/rendezvous.pb.go @@ -0,0 +1,324 @@ +// Code generated by protoc-gen-gogo. +// source: rendezvous.proto +// DO NOT EDIT! + +/* +Package rendezvous_pb is a generated protocol buffer package. + +It is generated from these files: + rendezvous.proto + +It has these top-level messages: + Message +*/ +package rendezvous_pb + +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 + +type Message_MessageType int32 + +const ( + Message_REGISTER Message_MessageType = 0 + Message_REGISTER_RESPONSE Message_MessageType = 1 + Message_UNREGISTER Message_MessageType = 2 + Message_DISCOVER Message_MessageType = 3 + Message_DISCOVER_RESPONSE Message_MessageType = 4 +) + +var Message_MessageType_name = map[int32]string{ + 0: "REGISTER", + 1: "REGISTER_RESPONSE", + 2: "UNREGISTER", + 3: "DISCOVER", + 4: "DISCOVER_RESPONSE", +} +var Message_MessageType_value = map[string]int32{ + "REGISTER": 0, + "REGISTER_RESPONSE": 1, + "UNREGISTER": 2, + "DISCOVER": 3, + "DISCOVER_RESPONSE": 4, +} + +func (x Message_MessageType) Enum() *Message_MessageType { + p := new(Message_MessageType) + *p = x + return p +} +func (x Message_MessageType) String() string { + return proto.EnumName(Message_MessageType_name, int32(x)) +} +func (x *Message_MessageType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Message_MessageType_value, data, "Message_MessageType") + if err != nil { + return err + } + *x = Message_MessageType(value) + return nil +} + +type Message_RegisterStatus int32 + +const ( + Message_OK Message_RegisterStatus = 0 + Message_E_INVALID_NAMESPACE Message_RegisterStatus = 100 + Message_E_INVALID_PEER_INFO Message_RegisterStatus = 101 + Message_E_NOT_AUTHORIZED Message_RegisterStatus = 200 +) + +var Message_RegisterStatus_name = map[int32]string{ + 0: "OK", + 100: "E_INVALID_NAMESPACE", + 101: "E_INVALID_PEER_INFO", + 200: "E_NOT_AUTHORIZED", +} +var Message_RegisterStatus_value = map[string]int32{ + "OK": 0, + "E_INVALID_NAMESPACE": 100, + "E_INVALID_PEER_INFO": 101, + "E_NOT_AUTHORIZED": 200, +} + +func (x Message_RegisterStatus) Enum() *Message_RegisterStatus { + p := new(Message_RegisterStatus) + *p = x + return p +} +func (x Message_RegisterStatus) String() string { + return proto.EnumName(Message_RegisterStatus_name, int32(x)) +} +func (x *Message_RegisterStatus) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Message_RegisterStatus_value, data, "Message_RegisterStatus") + if err != nil { + return err + } + *x = Message_RegisterStatus(value) + return nil +} + +type Message struct { + Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=rendezvous.pb.Message_MessageType" json:"type,omitempty"` + Register *Message_Register `protobuf:"bytes,2,opt,name=register" json:"register,omitempty"` + RegisterResponse *Message_RegisterResponse `protobuf:"bytes,3,opt,name=registerResponse" json:"registerResponse,omitempty"` + Unregister *Message_Unregister `protobuf:"bytes,4,opt,name=unregister" json:"unregister,omitempty"` + Discover *Message_Discover `protobuf:"bytes,5,opt,name=discover" json:"discover,omitempty"` + DiscoverResponse *Message_DiscoverResponse `protobuf:"bytes,6,opt,name=discoverResponse" json:"discoverResponse,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} + +func (m *Message) GetType() Message_MessageType { + if m != nil && m.Type != nil { + return *m.Type + } + return Message_REGISTER +} + +func (m *Message) GetRegister() *Message_Register { + if m != nil { + return m.Register + } + return nil +} + +func (m *Message) GetRegisterResponse() *Message_RegisterResponse { + if m != nil { + return m.RegisterResponse + } + return nil +} + +func (m *Message) GetUnregister() *Message_Unregister { + if m != nil { + return m.Unregister + } + return nil +} + +func (m *Message) GetDiscover() *Message_Discover { + if m != nil { + return m.Discover + } + return nil +} + +func (m *Message) GetDiscoverResponse() *Message_DiscoverResponse { + if m != nil { + return m.DiscoverResponse + } + return nil +} + +type Message_PeerInfo struct { + Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_PeerInfo) Reset() { *m = Message_PeerInfo{} } +func (m *Message_PeerInfo) String() string { return proto.CompactTextString(m) } +func (*Message_PeerInfo) ProtoMessage() {} + +func (m *Message_PeerInfo) GetId() []byte { + if m != nil { + return m.Id + } + return nil +} + +func (m *Message_PeerInfo) GetAddrs() [][]byte { + if m != nil { + return m.Addrs + } + return nil +} + +type Message_Register struct { + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Peer *Message_PeerInfo `protobuf:"bytes,2,opt,name=peer" json:"peer,omitempty"` + Ttl *int64 `protobuf:"varint,3,opt,name=ttl" json:"ttl,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_Register) Reset() { *m = Message_Register{} } +func (m *Message_Register) String() string { return proto.CompactTextString(m) } +func (*Message_Register) ProtoMessage() {} + +func (m *Message_Register) GetNs() string { + if m != nil && m.Ns != nil { + return *m.Ns + } + return "" +} + +func (m *Message_Register) GetPeer() *Message_PeerInfo { + if m != nil { + return m.Peer + } + return nil +} + +func (m *Message_Register) GetTtl() int64 { + if m != nil && m.Ttl != nil { + return *m.Ttl + } + return 0 +} + +type Message_RegisterResponse struct { + Status *Message_RegisterStatus `protobuf:"varint,1,opt,name=status,enum=rendezvous.pb.Message_RegisterStatus" json:"status,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_RegisterResponse) Reset() { *m = Message_RegisterResponse{} } +func (m *Message_RegisterResponse) String() string { return proto.CompactTextString(m) } +func (*Message_RegisterResponse) ProtoMessage() {} + +func (m *Message_RegisterResponse) GetStatus() Message_RegisterStatus { + if m != nil && m.Status != nil { + return *m.Status + } + return Message_OK +} + +type Message_Unregister struct { + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Id []byte `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_Unregister) Reset() { *m = Message_Unregister{} } +func (m *Message_Unregister) String() string { return proto.CompactTextString(m) } +func (*Message_Unregister) ProtoMessage() {} + +func (m *Message_Unregister) GetNs() string { + if m != nil && m.Ns != nil { + return *m.Ns + } + return "" +} + +func (m *Message_Unregister) GetId() []byte { + if m != nil { + return m.Id + } + return nil +} + +type Message_Discover struct { + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Limit *int64 `protobuf:"varint,2,opt,name=limit" json:"limit,omitempty"` + Cookie []byte `protobuf:"bytes,3,opt,name=cookie" json:"cookie,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_Discover) Reset() { *m = Message_Discover{} } +func (m *Message_Discover) String() string { return proto.CompactTextString(m) } +func (*Message_Discover) ProtoMessage() {} + +func (m *Message_Discover) GetNs() string { + if m != nil && m.Ns != nil { + return *m.Ns + } + return "" +} + +func (m *Message_Discover) GetLimit() int64 { + if m != nil && m.Limit != nil { + return *m.Limit + } + return 0 +} + +func (m *Message_Discover) GetCookie() []byte { + if m != nil { + return m.Cookie + } + return nil +} + +type Message_DiscoverResponse struct { + Registrations []*Message_Register `protobuf:"bytes,1,rep,name=registrations" json:"registrations,omitempty"` + Cookie []byte `protobuf:"bytes,2,opt,name=cookie" json:"cookie,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message_DiscoverResponse) Reset() { *m = Message_DiscoverResponse{} } +func (m *Message_DiscoverResponse) String() string { return proto.CompactTextString(m) } +func (*Message_DiscoverResponse) ProtoMessage() {} + +func (m *Message_DiscoverResponse) GetRegistrations() []*Message_Register { + if m != nil { + return m.Registrations + } + return nil +} + +func (m *Message_DiscoverResponse) GetCookie() []byte { + if m != nil { + return m.Cookie + } + return nil +} + +func init() { + proto.RegisterType((*Message)(nil), "rendezvous.pb.Message") + proto.RegisterType((*Message_PeerInfo)(nil), "rendezvous.pb.Message.PeerInfo") + proto.RegisterType((*Message_Register)(nil), "rendezvous.pb.Message.Register") + proto.RegisterType((*Message_RegisterResponse)(nil), "rendezvous.pb.Message.RegisterResponse") + proto.RegisterType((*Message_Unregister)(nil), "rendezvous.pb.Message.Unregister") + proto.RegisterType((*Message_Discover)(nil), "rendezvous.pb.Message.Discover") + proto.RegisterType((*Message_DiscoverResponse)(nil), "rendezvous.pb.Message.DiscoverResponse") + proto.RegisterEnum("rendezvous.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value) + proto.RegisterEnum("rendezvous.pb.Message_RegisterStatus", Message_RegisterStatus_name, Message_RegisterStatus_value) +} diff --git a/pb/rendezvous.proto b/pb/rendezvous.proto new file mode 100644 index 0000000..6e719ce --- /dev/null +++ b/pb/rendezvous.proto @@ -0,0 +1,56 @@ +package rendezvous.pb; + +message Message { + enum MessageType { + REGISTER = 0; + REGISTER_RESPONSE = 1; + UNREGISTER = 2; + DISCOVER = 3; + DISCOVER_RESPONSE = 4; + } + + message PeerInfo { + optional bytes id = 1; + repeated bytes addrs = 2; + } + + message Register { + optional string ns = 1; + optional PeerInfo peer = 2; + optional int64 ttl = 3; // in seconds + } + + enum RegisterStatus { + OK = 0; + E_INVALID_NAMESPACE = 100; + E_INVALID_PEER_INFO = 101; + E_NOT_AUTHORIZED = 200; + } + + message RegisterResponse { + optional RegisterStatus status = 1; + } + + message Unregister { + optional string ns = 1; + optional bytes id = 2; + } + + message Discover { + optional string ns = 1; + optional int64 limit = 2; + optional bytes cookie = 3; + } + + message DiscoverResponse { + repeated Register registrations = 1; + optional bytes cookie = 2; + } + + optional MessageType type = 1; + optional Register register = 2; + optional RegisterResponse registerResponse = 3; + optional Unregister unregister = 4; + optional Discover discover = 5; + optional DiscoverResponse discoverResponse = 6; +} From 0cbcbf6e24e015810de9bce984c287f230daf6b3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 19 Apr 2018 20:18:42 +0300 Subject: [PATCH 02/47] client implementation --- client.go | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 63 +++++++++++++++++ proto.go | 77 +++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 client.go create mode 100644 package.json create mode 100644 proto.go diff --git a/client.go b/client.go new file mode 100644 index 0000000..2d20bbc --- /dev/null +++ b/client.go @@ -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 + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..cf8f9f1 --- /dev/null +++ b/package.json @@ -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" +} + diff --git a/proto.go b/proto.go new file mode 100644 index 0000000..9021c5c --- /dev/null +++ b/proto.go @@ -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 +} From f94b0b48b32956a91d3672cda4850eacdf186ebe Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 19 Apr 2018 20:37:48 +0300 Subject: [PATCH 03/47] update client interface It's DiscoverOnce and Discover instead of Discover and DiscoverAsync --- client.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 2d20bbc..e04745e 100644 --- a/client.go +++ b/client.go @@ -20,8 +20,8 @@ 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) + DiscoverOnce(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error) + Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) } func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { @@ -82,7 +82,7 @@ func (cli *client) Unregister(ctx context.Context, ns string) error { return w.WriteMsg(req) } -func (cli *client) Discover(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error) { +func (cli *client) DiscoverOnce(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 @@ -122,7 +122,7 @@ func (cli *client) Discover(ctx context.Context, ns string, limit int) ([]pstore return pinfos, nil } -func (cli *client) DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { +func (cli *client) Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return nil, err From 268abf33570626471189784d8da71da800ad8e80 Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 19 Apr 2018 22:29:52 +0300 Subject: [PATCH 04/47] more fine-grained rendezvous api --- client.go | 108 +++++++++++++++++++++++++++++++----------------------- proto.go | 5 ++- 2 files changed, 67 insertions(+), 46 deletions(-) diff --git a/client.go b/client.go index e04745e..1b01c31 100644 --- a/client.go +++ b/client.go @@ -18,9 +18,10 @@ import ( var log = logging.Logger("rendezvous") type Rendezvous interface { - Register(ctx context.Context, ns string, ttl int) error + RegisterOnce(ctx context.Context, ns string, ttl int) error + Register(ctx context.Context, ns string) error Unregister(ctx context.Context, ns string) error - DiscoverOnce(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error) + DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) } @@ -36,18 +37,22 @@ type client struct { rp peer.ID } -func (cli *client) Register(ctx context.Context, ns string, ttl int) error { +func (cli *client) RegisterOnce(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() + return cli.registerOnce(ctx, ns, ttl, s) +} + +func (cli *client) registerOnce(ctx context.Context, ns string, ttl int, s inet.Stream) error { 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) + err := w.WriteMsg(req) if err != nil { return err } @@ -70,6 +75,36 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { return nil } +func (cli *client) Register(ctx context.Context, ns string) error { + s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) + if err != nil { + return err + } + + go cli.doRegister(ctx, ns, s) + return nil +} + +func (cli *client) doRegister(ctx context.Context, ns string, s inet.Stream) { + const ttl = 2 * 3600 // 2hr + const refresh = ttl - 30 + + defer s.Close() + for { + err := cli.registerOnce(ctx, ns, ttl, s) + if err != nil { + log.Errorf("Error registering: %s", err.Error()) + return + } + + select { + case <-time.After(refresh * time.Second): + case <-ctx.Done(): + return + } + } +} + func (cli *client) Unregister(ctx context.Context, ns string) error { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { @@ -82,30 +117,34 @@ func (cli *client) Unregister(ctx context.Context, ns string) error { return w.WriteMsg(req) } -func (cli *client) DiscoverOnce(ctx context.Context, ns string, limit int) ([]pstore.PeerInfo, error) { +func (cli *client) DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { - return nil, err + return nil, nil, err } defer s.Close() + return cli.discoverOnce(ctx, ns, limit, cookie, s) +} + +func (cli *client) discoverOnce(ctx context.Context, ns string, limit int, cookie []byte, s inet.Stream) ([]pstore.PeerInfo, []byte, error) { r := ggio.NewDelimitedReader(s, 1<<20) w := ggio.NewDelimitedWriter(s) - req := newDiscoverMessage(ns, limit) - err = w.WriteMsg(req) + req := newDiscoverMessage(ns, limit, cookie) + err := w.WriteMsg(req) if err != nil { - return nil, err + return nil, nil, err } var res pb.Message err = r.ReadMsg(&res) if err != nil { - return nil, err + return nil, nil, err } if res.GetType() != pb.Message_DISCOVER_RESPONSE { - return nil, fmt.Errorf("Unexpected response: %s", res.GetType().String()) + return nil, nil, fmt.Errorf("Unexpected response: %s", res.GetType().String()) } regs := res.GetDiscoverResponse().GetRegistrations() @@ -119,7 +158,7 @@ func (cli *client) DiscoverOnce(ctx context.Context, ns string, limit int) ([]ps pinfos = append(pinfos, pi) } - return pinfos, nil + return pinfos, res.GetDiscoverResponse().GetCookie(), nil } func (cli *client) Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { @@ -129,58 +168,37 @@ func (cli *client) Discover(ctx context.Context, ns string) (<-chan pstore.PeerI } ch := make(chan pstore.PeerInfo) - go doDiscovery(ctx, ns, s, ch) + go cli.doDiscover(ctx, ns, s, ch) return ch, nil } -func doDiscovery(ctx context.Context, ns string, s inet.Stream, ch chan pstore.PeerInfo) { +func (cli *client) doDiscover(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) - + var ( + cookie []byte + pi []pstore.PeerInfo + err error + ) for { - err := w.WriteMsg(req) + pi, cookie, err = cli.discoverOnce(ctx, ns, batch, cookie, s) if err != nil { - log.Errorf("Error sending Discover request: %s", err.Error()) + log.Errorf("Error in discovery: %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 - } - + for _, p := range pi { select { - case ch <- pinfo: + case ch <- p: case <-ctx.Done(): return } } - req.Discover.Cookie = res.GetDiscoverResponse().GetCookie() - - if len(regs) < batch { + if len(pi) < batch { select { case <-time.After(1 * time.Minute): case <-ctx.Done(): diff --git a/proto.go b/proto.go index 9021c5c..2ca1d3e 100644 --- a/proto.go +++ b/proto.go @@ -44,7 +44,7 @@ func newUnregisterMessage(ns string, pid peer.ID) *pb.Message { return msg } -func newDiscoverMessage(ns string, limit int) *pb.Message { +func newDiscoverMessage(ns string, limit int, cookie []byte) *pb.Message { msg := new(pb.Message) msg.Type = pb.Message_DISCOVER.Enum() msg.Discover = new(pb.Message_Discover) @@ -55,6 +55,9 @@ func newDiscoverMessage(ns string, limit int) *pb.Message { limit64 := int64(limit) msg.Discover.Limit = &limit64 } + if cookie != nil { + msg.Discover.Cookie = cookie + } return msg } From b7bc940aedf4e3b07425de0d152c57596a57e76d Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 19 Apr 2018 22:34:46 +0300 Subject: [PATCH 05/47] add error notification for background register/discover --- client.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/client.go b/client.go index 1b01c31..4f31a0b 100644 --- a/client.go +++ b/client.go @@ -19,10 +19,10 @@ var log = logging.Logger("rendezvous") type Rendezvous interface { RegisterOnce(ctx context.Context, ns string, ttl int) error - Register(ctx context.Context, ns string) error + Register(ctx context.Context, ns string, E func(error)) error Unregister(ctx context.Context, ns string) error DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) - Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) + Discover(ctx context.Context, ns string, E func(error)) (<-chan pstore.PeerInfo, error) } func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { @@ -75,17 +75,17 @@ func (cli *client) registerOnce(ctx context.Context, ns string, ttl int, s inet. return nil } -func (cli *client) Register(ctx context.Context, ns string) error { +func (cli *client) Register(ctx context.Context, ns string, E func(error)) error { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return err } - go cli.doRegister(ctx, ns, s) + go cli.doRegister(ctx, ns, E, s) return nil } -func (cli *client) doRegister(ctx context.Context, ns string, s inet.Stream) { +func (cli *client) doRegister(ctx context.Context, ns string, E func(error), s inet.Stream) { const ttl = 2 * 3600 // 2hr const refresh = ttl - 30 @@ -94,6 +94,9 @@ func (cli *client) doRegister(ctx context.Context, ns string, s inet.Stream) { err := cli.registerOnce(ctx, ns, ttl, s) if err != nil { log.Errorf("Error registering: %s", err.Error()) + if E != nil { + go E(err) + } return } @@ -161,18 +164,18 @@ func (cli *client) discoverOnce(ctx context.Context, ns string, limit int, cooki return pinfos, res.GetDiscoverResponse().GetCookie(), nil } -func (cli *client) Discover(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { +func (cli *client) Discover(ctx context.Context, ns string, E func(error)) (<-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 cli.doDiscover(ctx, ns, s, ch) + go cli.doDiscover(ctx, ns, E, s, ch) return ch, nil } -func (cli *client) doDiscover(ctx context.Context, ns string, s inet.Stream, ch chan pstore.PeerInfo) { +func (cli *client) doDiscover(ctx context.Context, ns string, E func(error), s inet.Stream, ch chan pstore.PeerInfo) { defer s.Close() defer close(ch) @@ -187,6 +190,9 @@ func (cli *client) doDiscover(ctx context.Context, ns string, s inet.Stream, ch pi, cookie, err = cli.discoverOnce(ctx, ns, batch, cookie, s) if err != nil { log.Errorf("Error in discovery: %s", err.Error()) + if E != nil { + go E(err) + } return } From a107e34a06d037c3dd401511c69695f894eca1bf Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 19 Apr 2018 22:46:13 +0300 Subject: [PATCH 06/47] interface ergonomics --- client.go | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 4f31a0b..b97242e 100644 --- a/client.go +++ b/client.go @@ -19,10 +19,10 @@ var log = logging.Logger("rendezvous") type Rendezvous interface { RegisterOnce(ctx context.Context, ns string, ttl int) error - Register(ctx context.Context, ns string, E func(error)) error + Register(ctx context.Context, ns string, opts ...interface{}) error Unregister(ctx context.Context, ns string) error DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) - Discover(ctx context.Context, ns string, E func(error)) (<-chan pstore.PeerInfo, error) + Discover(ctx context.Context, ns string, opts ...interface{}) (<-chan pstore.PeerInfo, error) } func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { @@ -75,7 +75,19 @@ func (cli *client) registerOnce(ctx context.Context, ns string, ttl int, s inet. return nil } -func (cli *client) Register(ctx context.Context, ns string, E func(error)) error { +func (cli *client) Register(ctx context.Context, ns string, opts ...interface{}) error { + var E func(error) + + for _, opt := range opts { + switch o := opt.(type) { + case func(error): + E = o + + default: + return fmt.Errorf("Unexpected option: %v", opt) + } + } + s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return err @@ -164,7 +176,19 @@ func (cli *client) discoverOnce(ctx context.Context, ns string, limit int, cooki return pinfos, res.GetDiscoverResponse().GetCookie(), nil } -func (cli *client) Discover(ctx context.Context, ns string, E func(error)) (<-chan pstore.PeerInfo, error) { +func (cli *client) Discover(ctx context.Context, ns string, opts ...interface{}) (<-chan pstore.PeerInfo, error) { + var E func(error) + + for _, opt := range opts { + switch o := opt.(type) { + case func(error): + E = o + + default: + return nil, fmt.Errorf("Unexpected option: %v", opt) + } + } + s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return nil, err From 13f4c67879a8bd967f7c66d068971db5e42686ad Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 20 Apr 2018 10:43:36 +0300 Subject: [PATCH 07/47] add E_INVALID_TTL to rendezvous.proto --- pb/rendezvous.pb.go | 3 +++ pb/rendezvous.proto | 1 + 2 files changed, 4 insertions(+) diff --git a/pb/rendezvous.pb.go b/pb/rendezvous.pb.go index 6396912..0c7cc5a 100644 --- a/pb/rendezvous.pb.go +++ b/pb/rendezvous.pb.go @@ -70,6 +70,7 @@ const ( Message_OK Message_RegisterStatus = 0 Message_E_INVALID_NAMESPACE Message_RegisterStatus = 100 Message_E_INVALID_PEER_INFO Message_RegisterStatus = 101 + Message_E_INVALID_TTL Message_RegisterStatus = 102 Message_E_NOT_AUTHORIZED Message_RegisterStatus = 200 ) @@ -77,12 +78,14 @@ var Message_RegisterStatus_name = map[int32]string{ 0: "OK", 100: "E_INVALID_NAMESPACE", 101: "E_INVALID_PEER_INFO", + 102: "E_INVALID_TTL", 200: "E_NOT_AUTHORIZED", } var Message_RegisterStatus_value = map[string]int32{ "OK": 0, "E_INVALID_NAMESPACE": 100, "E_INVALID_PEER_INFO": 101, + "E_INVALID_TTL": 102, "E_NOT_AUTHORIZED": 200, } diff --git a/pb/rendezvous.proto b/pb/rendezvous.proto index 6e719ce..07b94db 100644 --- a/pb/rendezvous.proto +++ b/pb/rendezvous.proto @@ -24,6 +24,7 @@ message Message { OK = 0; E_INVALID_NAMESPACE = 100; E_INVALID_PEER_INFO = 101; + E_INVALID_TTL = 102; E_NOT_AUTHORIZED = 200; } From e3d343f34a79356847ef97927c0707b706785f91 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 20 Apr 2018 12:01:35 +0300 Subject: [PATCH 08/47] include namespace in error logs --- client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index b97242e..2f64ebb 100644 --- a/client.go +++ b/client.go @@ -105,7 +105,7 @@ func (cli *client) doRegister(ctx context.Context, ns string, E func(error), s i for { err := cli.registerOnce(ctx, ns, ttl, s) if err != nil { - log.Errorf("Error registering: %s", err.Error()) + log.Errorf("Error registering [%s]: %s", ns, err.Error()) if E != nil { go E(err) } @@ -213,7 +213,7 @@ func (cli *client) doDiscover(ctx context.Context, ns string, E func(error), s i for { pi, cookie, err = cli.discoverOnce(ctx, ns, batch, cookie, s) if err != nil { - log.Errorf("Error in discovery: %s", err.Error()) + log.Errorf("Error in discovery [%s]: %s", ns, err.Error()) if E != nil { go E(err) } From 1506c04f1ae3ef4709e1d6359833a1623c43583e Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 20 Apr 2018 13:07:01 +0300 Subject: [PATCH 09/47] simplify Rendezvous interface --- client.go | 95 +++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 63 deletions(-) diff --git a/client.go b/client.go index 2f64ebb..97c5f05 100644 --- a/client.go +++ b/client.go @@ -17,12 +17,13 @@ import ( var log = logging.Logger("rendezvous") +const DefaultTTL = 2 * 3600 // 2hr + type Rendezvous interface { - RegisterOnce(ctx context.Context, ns string, ttl int) error - Register(ctx context.Context, ns string, opts ...interface{}) error + Register(ctx context.Context, ns string, ttl int) error Unregister(ctx context.Context, ns string) error - DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) - Discover(ctx context.Context, ns string, opts ...interface{}) (<-chan pstore.PeerInfo, error) + Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) + DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) } func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { @@ -37,22 +38,18 @@ type client struct { rp peer.ID } -func (cli *client) RegisterOnce(ctx context.Context, ns string, ttl int) error { +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() - return cli.registerOnce(ctx, ns, ttl, s) -} - -func (cli *client) registerOnce(ctx context.Context, ns string, ttl int, s inet.Stream) error { 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) + err = w.WriteMsg(req) if err != nil { return err } @@ -75,48 +72,30 @@ func (cli *client) registerOnce(ctx context.Context, ns string, ttl int, s inet. return nil } -func (cli *client) Register(ctx context.Context, ns string, opts ...interface{}) error { - var E func(error) - - for _, opt := range opts { - switch o := opt.(type) { - case func(error): - E = o - - default: - return fmt.Errorf("Unexpected option: %v", opt) - } - } - - s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) +func Register(ctx context.Context, rz Rendezvous, ns string) error { + err := rz.Register(ctx, ns, DefaultTTL) if err != nil { return err } - go cli.doRegister(ctx, ns, E, s) + go registerRefresh(ctx, rz, ns) return nil } -func (cli *client) doRegister(ctx context.Context, ns string, E func(error), s inet.Stream) { - const ttl = 2 * 3600 // 2hr - const refresh = ttl - 30 +func registerRefresh(ctx context.Context, rz Rendezvous, ns string) { + const refresh = DefaultTTL - 30 - defer s.Close() for { - err := cli.registerOnce(ctx, ns, ttl, s) - if err != nil { - log.Errorf("Error registering [%s]: %s", ns, err.Error()) - if E != nil { - go E(err) - } - return - } - select { case <-time.After(refresh * time.Second): case <-ctx.Done(): return } + + err := rz.Register(ctx, ns, DefaultTTL) + if err != nil { + log.Errorf("Error registering [%s]: %s", ns, err.Error()) + } } } @@ -132,20 +111,21 @@ func (cli *client) Unregister(ctx context.Context, ns string) error { return w.WriteMsg(req) } -func (cli *client) DiscoverOnce(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { +func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return nil, nil, err } defer s.Close() - return cli.discoverOnce(ctx, ns, limit, cookie, s) -} - -func (cli *client) discoverOnce(ctx context.Context, ns string, limit int, cookie []byte, s inet.Stream) ([]pstore.PeerInfo, []byte, error) { r := ggio.NewDelimitedReader(s, 1<<20) w := ggio.NewDelimitedWriter(s) + return discoverQuery(ns, limit, cookie, r, w) +} + +func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Writer) ([]pstore.PeerInfo, []byte, error) { + req := newDiscoverMessage(ns, limit, cookie) err := w.WriteMsg(req) if err != nil { @@ -176,33 +156,24 @@ func (cli *client) discoverOnce(ctx context.Context, ns string, limit int, cooki return pinfos, res.GetDiscoverResponse().GetCookie(), nil } -func (cli *client) Discover(ctx context.Context, ns string, opts ...interface{}) (<-chan pstore.PeerInfo, error) { - var E func(error) - - for _, opt := range opts { - switch o := opt.(type) { - case func(error): - E = o - - default: - return nil, fmt.Errorf("Unexpected option: %v", opt) - } - } - +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 cli.doDiscover(ctx, ns, E, s, ch) + go discoverAsync(ctx, ns, s, ch) return ch, nil } -func (cli *client) doDiscover(ctx context.Context, ns string, E func(error), s inet.Stream, ch chan pstore.PeerInfo) { +func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan pstore.PeerInfo) { defer s.Close() defer close(ch) + r := ggio.NewDelimitedReader(s, 1<<20) + w := ggio.NewDelimitedWriter(s) + const batch = 100 var ( @@ -210,13 +181,11 @@ func (cli *client) doDiscover(ctx context.Context, ns string, E func(error), s i pi []pstore.PeerInfo err error ) + for { - pi, cookie, err = cli.discoverOnce(ctx, ns, batch, cookie, s) + pi, cookie, err = discoverQuery(ns, batch, cookie, r, w) if err != nil { log.Errorf("Error in discovery [%s]: %s", ns, err.Error()) - if E != nil { - go E(err) - } return } @@ -230,7 +199,7 @@ func (cli *client) doDiscover(ctx context.Context, ns string, E func(error), s i if len(pi) < batch { select { - case <-time.After(1 * time.Minute): + case <-time.After(2 * time.Minute): case <-ctx.Done(): return } From 7e5664ce7c3332189e98ae5772506dccf02e97df Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 20 Apr 2018 14:38:12 +0300 Subject: [PATCH 10/47] use discriminated registration errors --- client.go | 2 +- proto.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 97c5f05..2ed61a5 100644 --- a/client.go +++ b/client.go @@ -66,7 +66,7 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { status := res.GetRegisterResponse().GetStatus() if status != pb.Message_OK { - return fmt.Errorf("Registration failure: %s", status.String()) + return RegistrationError(status) } return nil diff --git a/proto.go b/proto.go index 2ca1d3e..cb29a69 100644 --- a/proto.go +++ b/proto.go @@ -13,6 +13,12 @@ const ( RendezvousProto = protocol.ID("/rendezvous/1.0.0") ) +type RegistrationError pb.Message_RegisterStatus + +func (e RegistrationError) Error() string { + return pb.Message_RegisterStatus(e).String() +} + func newRegisterMessage(ns string, pi pstore.PeerInfo, ttl int) *pb.Message { msg := new(pb.Message) msg.Type = pb.Message_REGISTER.Enum() From 6a1176f84479d027ff184285f6615815c4a862fc Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 20 Apr 2018 19:20:04 +0300 Subject: [PATCH 11/47] annotate registration error --- proto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto.go b/proto.go index cb29a69..1b1ae0e 100644 --- a/proto.go +++ b/proto.go @@ -16,7 +16,7 @@ const ( type RegistrationError pb.Message_RegisterStatus func (e RegistrationError) Error() string { - return pb.Message_RegisterStatus(e).String() + return "Registration error: " + pb.Message_RegisterStatus(e).String() } func newRegisterMessage(ns string, pi pstore.PeerInfo, ttl int) *pb.Message { From b7c304ddf370e0b088ab6883aec9c712f3b7a52e Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 21 Apr 2018 12:05:36 +0300 Subject: [PATCH 12/47] update protobuf --- pb/rendezvous.pb.go | 72 ++++++++++++++++++++++++++++++++------------- pb/rendezvous.proto | 23 +++++++++------ 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/pb/rendezvous.pb.go b/pb/rendezvous.pb.go index 0c7cc5a..a8b8751 100644 --- a/pb/rendezvous.pb.go +++ b/pb/rendezvous.pb.go @@ -64,45 +64,51 @@ func (x *Message_MessageType) UnmarshalJSON(data []byte) error { return nil } -type Message_RegisterStatus int32 +type Message_ResponseStatus int32 const ( - Message_OK Message_RegisterStatus = 0 - Message_E_INVALID_NAMESPACE Message_RegisterStatus = 100 - Message_E_INVALID_PEER_INFO Message_RegisterStatus = 101 - Message_E_INVALID_TTL Message_RegisterStatus = 102 - Message_E_NOT_AUTHORIZED Message_RegisterStatus = 200 + Message_OK Message_ResponseStatus = 0 + Message_E_INVALID_NAMESPACE Message_ResponseStatus = 100 + Message_E_INVALID_PEER_INFO Message_ResponseStatus = 101 + Message_E_INVALID_TTL Message_ResponseStatus = 102 + Message_E_INVALID_COOKIE Message_ResponseStatus = 103 + Message_E_NOT_AUTHORIZED Message_ResponseStatus = 200 + Message_E_INTERNAL_ERROR Message_ResponseStatus = 300 ) -var Message_RegisterStatus_name = map[int32]string{ +var Message_ResponseStatus_name = map[int32]string{ 0: "OK", 100: "E_INVALID_NAMESPACE", 101: "E_INVALID_PEER_INFO", 102: "E_INVALID_TTL", + 103: "E_INVALID_COOKIE", 200: "E_NOT_AUTHORIZED", + 300: "E_INTERNAL_ERROR", } -var Message_RegisterStatus_value = map[string]int32{ +var Message_ResponseStatus_value = map[string]int32{ "OK": 0, "E_INVALID_NAMESPACE": 100, "E_INVALID_PEER_INFO": 101, "E_INVALID_TTL": 102, + "E_INVALID_COOKIE": 103, "E_NOT_AUTHORIZED": 200, + "E_INTERNAL_ERROR": 300, } -func (x Message_RegisterStatus) Enum() *Message_RegisterStatus { - p := new(Message_RegisterStatus) +func (x Message_ResponseStatus) Enum() *Message_ResponseStatus { + p := new(Message_ResponseStatus) *p = x return p } -func (x Message_RegisterStatus) String() string { - return proto.EnumName(Message_RegisterStatus_name, int32(x)) +func (x Message_ResponseStatus) String() string { + return proto.EnumName(Message_ResponseStatus_name, int32(x)) } -func (x *Message_RegisterStatus) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Message_RegisterStatus_value, data, "Message_RegisterStatus") +func (x *Message_ResponseStatus) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Message_ResponseStatus_value, data, "Message_ResponseStatus") if err != nil { return err } - *x = Message_RegisterStatus(value) + *x = Message_ResponseStatus(value) return nil } @@ -219,7 +225,8 @@ func (m *Message_Register) GetTtl() int64 { } type Message_RegisterResponse struct { - Status *Message_RegisterStatus `protobuf:"varint,1,opt,name=status,enum=rendezvous.pb.Message_RegisterStatus" json:"status,omitempty"` + Status *Message_ResponseStatus `protobuf:"varint,1,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` + StatusText *string `protobuf:"bytes,2,opt,name=statusText" json:"statusText,omitempty"` XXX_unrecognized []byte `json:"-"` } @@ -227,13 +234,20 @@ func (m *Message_RegisterResponse) Reset() { *m = Message_RegisterRespon func (m *Message_RegisterResponse) String() string { return proto.CompactTextString(m) } func (*Message_RegisterResponse) ProtoMessage() {} -func (m *Message_RegisterResponse) GetStatus() Message_RegisterStatus { +func (m *Message_RegisterResponse) GetStatus() Message_ResponseStatus { if m != nil && m.Status != nil { return *m.Status } return Message_OK } +func (m *Message_RegisterResponse) GetStatusText() string { + if m != nil && m.StatusText != nil { + return *m.StatusText + } + return "" +} + type Message_Unregister struct { Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` Id []byte `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` @@ -291,9 +305,11 @@ func (m *Message_Discover) GetCookie() []byte { } type Message_DiscoverResponse struct { - Registrations []*Message_Register `protobuf:"bytes,1,rep,name=registrations" json:"registrations,omitempty"` - Cookie []byte `protobuf:"bytes,2,opt,name=cookie" json:"cookie,omitempty"` - XXX_unrecognized []byte `json:"-"` + Registrations []*Message_Register `protobuf:"bytes,1,rep,name=registrations" json:"registrations,omitempty"` + Cookie []byte `protobuf:"bytes,2,opt,name=cookie" json:"cookie,omitempty"` + Status *Message_ResponseStatus `protobuf:"varint,3,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` + StatusText *string `protobuf:"bytes,4,opt,name=statusText" json:"statusText,omitempty"` + XXX_unrecognized []byte `json:"-"` } func (m *Message_DiscoverResponse) Reset() { *m = Message_DiscoverResponse{} } @@ -314,6 +330,20 @@ func (m *Message_DiscoverResponse) GetCookie() []byte { return nil } +func (m *Message_DiscoverResponse) GetStatus() Message_ResponseStatus { + if m != nil && m.Status != nil { + return *m.Status + } + return Message_OK +} + +func (m *Message_DiscoverResponse) GetStatusText() string { + if m != nil && m.StatusText != nil { + return *m.StatusText + } + return "" +} + func init() { proto.RegisterType((*Message)(nil), "rendezvous.pb.Message") proto.RegisterType((*Message_PeerInfo)(nil), "rendezvous.pb.Message.PeerInfo") @@ -323,5 +353,5 @@ func init() { proto.RegisterType((*Message_Discover)(nil), "rendezvous.pb.Message.Discover") proto.RegisterType((*Message_DiscoverResponse)(nil), "rendezvous.pb.Message.DiscoverResponse") proto.RegisterEnum("rendezvous.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value) - proto.RegisterEnum("rendezvous.pb.Message_RegisterStatus", Message_RegisterStatus_name, Message_RegisterStatus_value) + proto.RegisterEnum("rendezvous.pb.Message_ResponseStatus", Message_ResponseStatus_name, Message_ResponseStatus_value) } diff --git a/pb/rendezvous.proto b/pb/rendezvous.proto index 07b94db..1526f54 100644 --- a/pb/rendezvous.proto +++ b/pb/rendezvous.proto @@ -9,6 +9,16 @@ message Message { DISCOVER_RESPONSE = 4; } + enum ResponseStatus { + OK = 0; + E_INVALID_NAMESPACE = 100; + E_INVALID_PEER_INFO = 101; + E_INVALID_TTL = 102; + E_INVALID_COOKIE = 103; + E_NOT_AUTHORIZED = 200; + E_INTERNAL_ERROR = 300; + } + message PeerInfo { optional bytes id = 1; repeated bytes addrs = 2; @@ -20,16 +30,9 @@ message Message { optional int64 ttl = 3; // in seconds } - enum RegisterStatus { - OK = 0; - E_INVALID_NAMESPACE = 100; - E_INVALID_PEER_INFO = 101; - E_INVALID_TTL = 102; - E_NOT_AUTHORIZED = 200; - } - message RegisterResponse { - optional RegisterStatus status = 1; + optional ResponseStatus status = 1; + optional string statusText = 2; } message Unregister { @@ -46,6 +49,8 @@ message Message { message DiscoverResponse { repeated Register registrations = 1; optional bytes cookie = 2; + optional ResponseStatus status = 3; + optional string statusText = 4; } optional MessageType type = 1; From aeac2e2a0f31cd23607eec2db3b8e4f90d298023 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 21 Apr 2018 12:06:27 +0300 Subject: [PATCH 13/47] update for response error changes in the protocol --- client.go | 7 ++++++- proto.go | 11 ++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/client.go b/client.go index 2ed61a5..dc629aa 100644 --- a/client.go +++ b/client.go @@ -66,7 +66,7 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { status := res.GetRegisterResponse().GetStatus() if status != pb.Message_OK { - return RegistrationError(status) + return RendezvousError{Status: status, Text: res.GetRegisterResponse().GetStatusText()} } return nil @@ -142,6 +142,11 @@ func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Wr return nil, nil, fmt.Errorf("Unexpected response: %s", res.GetType().String()) } + status := res.GetDiscoverResponse().GetStatus() + if status != pb.Message_OK { + return nil, nil, RendezvousError{Status: status, Text: res.GetDiscoverResponse().GetStatusText()} + } + regs := res.GetDiscoverResponse().GetRegistrations() pinfos := make([]pstore.PeerInfo, 0, len(regs)) for _, reg := range regs { diff --git a/proto.go b/proto.go index 1b1ae0e..ae3941d 100644 --- a/proto.go +++ b/proto.go @@ -1,6 +1,8 @@ package rendezvous import ( + "fmt" + pb "github.com/libp2p/go-libp2p-rendezvous/pb" peer "github.com/libp2p/go-libp2p-peer" @@ -13,10 +15,13 @@ const ( RendezvousProto = protocol.ID("/rendezvous/1.0.0") ) -type RegistrationError pb.Message_RegisterStatus +type RendezvousError struct { + Status pb.Message_ResponseStatus + Text string +} -func (e RegistrationError) Error() string { - return "Registration error: " + pb.Message_RegisterStatus(e).String() +func (e RendezvousError) Error() string { + return fmt.Sprintf("Rendezvous error: %s (%s)", e.Text, pb.Message_ResponseStatus(e.Status).String()) } func newRegisterMessage(ns string, pi pstore.PeerInfo, ttl int) *pb.Message { From e5a72b9bea5ecd8f9c908b804816dc81a0ebc1e2 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 21 Apr 2018 18:51:18 +0300 Subject: [PATCH 14/47] rendezvous interface should expose full registration information - instead of returning PeerInfos, return Registration objects in discovery - provide utility functions at module level for peer info discovery --- client.go | 81 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/client.go b/client.go index dc629aa..6e31404 100644 --- a/client.go +++ b/client.go @@ -22,8 +22,14 @@ const DefaultTTL = 2 * 3600 // 2hr 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, cookie []byte) ([]pstore.PeerInfo, []byte, error) - DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) + Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]Registration, []byte, error) + DiscoverAsync(ctx context.Context, ns string) (<-chan Registration, error) +} + +type Registration struct { + Peer pstore.PeerInfo + Ns string + Ttl int } func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { @@ -111,7 +117,7 @@ func (cli *client) Unregister(ctx context.Context, ns string) error { return w.WriteMsg(req) } -func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { +func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]Registration, []byte, error) { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return nil, nil, err @@ -124,7 +130,7 @@ func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie [] return discoverQuery(ns, limit, cookie, r, w) } -func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Writer) ([]pstore.PeerInfo, []byte, error) { +func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Writer) ([]Registration, []byte, error) { req := newDiscoverMessage(ns, limit, cookie) err := w.WriteMsg(req) @@ -148,31 +154,31 @@ func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Wr } regs := res.GetDiscoverResponse().GetRegistrations() - pinfos := make([]pstore.PeerInfo, 0, len(regs)) + result := make([]Registration, 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) + result = append(result, Registration{Peer: pi, Ns: reg.GetNs(), Ttl: int(reg.GetTtl())}) } - return pinfos, res.GetDiscoverResponse().GetCookie(), nil + return result, res.GetDiscoverResponse().GetCookie(), nil } -func (cli *client) DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { +func (cli *client) DiscoverAsync(ctx context.Context, ns string) (<-chan Registration, error) { s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) if err != nil { return nil, err } - ch := make(chan pstore.PeerInfo) + ch := make(chan Registration) go discoverAsync(ctx, ns, s, ch) return ch, nil } -func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan pstore.PeerInfo) { +func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Registration) { defer s.Close() defer close(ch) @@ -183,26 +189,26 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan pstore var ( cookie []byte - pi []pstore.PeerInfo + regs []Registration err error ) for { - pi, cookie, err = discoverQuery(ns, batch, cookie, r, w) + regs, cookie, err = discoverQuery(ns, batch, cookie, r, w) if err != nil { log.Errorf("Error in discovery [%s]: %s", ns, err.Error()) return } - for _, p := range pi { + for _, reg := range regs { select { - case ch <- p: + case ch <- reg: case <-ctx.Done(): return } } - if len(pi) < batch { + if len(regs) < batch { select { case <-time.After(2 * time.Minute): case <-ctx.Done(): @@ -211,3 +217,48 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan pstore } } } + +func DiscoverPeers(ctx context.Context, rz Rendezvous, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { + regs, cookie, err := rz.Discover(ctx, ns, limit, cookie) + if err != nil { + return nil, nil, err + } + + pinfos := make([]pstore.PeerInfo, len(regs)) + for i, reg := range regs { + pinfos[i] = reg.Peer + } + + return pinfos, cookie, nil +} + +func DiscoverPeersAsync(ctx context.Context, rz Rendezvous, ns string) (<-chan pstore.PeerInfo, error) { + rch, err := rz.DiscoverAsync(ctx, ns) + if err != nil { + return nil, err + } + + ch := make(chan pstore.PeerInfo) + go discoverPeersAsync(ctx, rch, ch) + return ch, nil +} + +func discoverPeersAsync(ctx context.Context, rch <-chan Registration, ch chan pstore.PeerInfo) { + defer close(ch) + for { + select { + case reg, ok := <-rch: + if !ok { + return + } + + select { + case ch <- reg.Peer: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } +} From 7d72fc79b3c0adffd71de5602648622e8a1e6ca2 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 11:54:25 +0300 Subject: [PATCH 15/47] service implementation --- client.go | 13 +--- db.go | 35 +++++++++ proto.go | 60 +++++++++++++++ svc.go | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+), 9 deletions(-) create mode 100644 db.go create mode 100644 svc.go diff --git a/client.go b/client.go index 6e31404..99995be 100644 --- a/client.go +++ b/client.go @@ -8,17 +8,12 @@ import ( 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") - -const DefaultTTL = 2 * 3600 // 2hr - type Rendezvous interface { Register(ctx context.Context, ns string, ttl int) error Unregister(ctx context.Context, ns string) error @@ -51,7 +46,7 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { } defer s.Close() - r := ggio.NewDelimitedReader(s, 1<<20) + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) req := newRegisterMessage(ns, pstore.PeerInfo{ID: cli.host.ID(), Addrs: cli.host.Addrs()}, ttl) @@ -124,7 +119,7 @@ func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie [] } defer s.Close() - r := ggio.NewDelimitedReader(s, 1<<20) + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) return discoverQuery(ns, limit, cookie, r, w) @@ -182,7 +177,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist defer s.Close() defer close(ch) - r := ggio.NewDelimitedReader(s, 1<<20) + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) const batch = 100 @@ -208,7 +203,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist } } - if len(regs) < batch { + if len(regs) < batch/2 { select { case <-time.After(2 * time.Minute): case <-ctx.Done(): diff --git a/db.go b/db.go new file mode 100644 index 0000000..cfee9cb --- /dev/null +++ b/db.go @@ -0,0 +1,35 @@ +package rendezvous + +import ( + "context" + "errors" + + peer "github.com/libp2p/go-libp2p-peer" +) + +type DB struct { +} + +func OpenDB(ctx context.Context, path string) (*DB, error) { + return nil, errors.New("IMPLEMENTME: OpenDB") +} + +func (db *DB) Register(p peer.ID, ns string, addrs [][]byte, ttl int) error { + return errors.New("IMPLEMENTME: DB.Register") +} + +func (db *DB) CountRegistrations(p peer.ID) (int, error) { + return 0, errors.New("IMPLEMENTME: DB.CountRegistrations") +} + +func (db *DB) Unregister(p peer.ID, ns string) error { + return errors.New("IMPLEMENTME: DB.Unregister") +} + +func (db *DB) ValidCookie(ns string, cookie []byte) bool { + return false +} + +func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecord, []byte, error) { + return nil, nil, errors.New("IMPLEMENTME: DB.Discover") +} diff --git a/proto.go b/proto.go index ae3941d..f1c48d6 100644 --- a/proto.go +++ b/proto.go @@ -1,20 +1,33 @@ package rendezvous import ( + "errors" "fmt" pb "github.com/libp2p/go-libp2p-rendezvous/pb" + logging "github.com/ipfs/go-log" 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" ) +var log = logging.Logger("rendezvous") + const ( RendezvousProto = protocol.ID("/rendezvous/1.0.0") + + DefaultTTL = 2 * 3600 // 2hr ) +type RegistrationRecord struct { + Id []byte + Addrs [][]byte + Ns string + Ttl int +} + type RendezvousError struct { Status pb.Message_ResponseStatus Text string @@ -73,6 +86,10 @@ func newDiscoverMessage(ns string, limit int, cookie []byte) *pb.Message { } func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) { + if p == nil { + return pstore.PeerInfo{}, errors.New("missing peer info") + } + id, err := peer.IDFromBytes(p.Id) if err != nil { return pstore.PeerInfo{}, err @@ -89,3 +106,46 @@ func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) { return pstore.PeerInfo{ID: id, Addrs: addrs}, nil } + +func newRegisterResponse() *pb.Message_RegisterResponse { + r := new(pb.Message_RegisterResponse) + r.Status = pb.Message_OK.Enum() + return r +} + +func newRegisterResponseError(status pb.Message_ResponseStatus, text string) *pb.Message_RegisterResponse { + r := new(pb.Message_RegisterResponse) + r.Status = status.Enum() + r.StatusText = &text + return r +} + +func newDiscoverResponse(regs []RegistrationRecord, cookie []byte) *pb.Message_DiscoverResponse { + r := new(pb.Message_DiscoverResponse) + r.Status = pb.Message_OK.Enum() + + rregs := make([]*pb.Message_Register, len(regs)) + for i, reg := range regs { + rreg := new(pb.Message_Register) + rns := reg.Ns + rreg.Ns = &rns + rreg.Peer = new(pb.Message_PeerInfo) + rreg.Peer.Id = reg.Id + rreg.Peer.Addrs = reg.Addrs + rttl := int64(reg.Ttl) + rreg.Ttl = &rttl + rregs[i] = rreg + } + + r.Registrations = rregs + r.Cookie = cookie + + return r +} + +func newDiscoverResponseError(status pb.Message_ResponseStatus, text string) *pb.Message_DiscoverResponse { + r := new(pb.Message_DiscoverResponse) + r.Status = status.Enum() + r.StatusText = &text + return r +} diff --git a/svc.go b/svc.go new file mode 100644 index 0000000..71b609a --- /dev/null +++ b/svc.go @@ -0,0 +1,213 @@ +package rendezvous + +import ( + "context" + "fmt" + + pb "github.com/libp2p/go-libp2p-rendezvous/pb" + + ggio "github.com/gogo/protobuf/io" + host "github.com/libp2p/go-libp2p-host" + inet "github.com/libp2p/go-libp2p-net" + peer "github.com/libp2p/go-libp2p-peer" +) + +const ( + MaxTTL = 72 * 3600 // 72hr + MaxNamespaceLength = 256 + MaxPeerAddressLength = 2048 + MaxRegistrations = 100 + MaxDiscoverLimit = 1000 +) + +type RendezvousService struct { + DB *DB +} + +func NewRendezvousService(ctx context.Context, host host.Host, dbpath string) (*RendezvousService, error) { + db, err := OpenDB(ctx, dbpath) + if err != nil { + return nil, err + } + + rz := &RendezvousService{DB: db} + host.SetStreamHandler(RendezvousProto, rz.handleStream) + return rz, nil +} + +func (rz *RendezvousService) handleStream(s inet.Stream) { + pid := s.Conn().RemotePeer() + log.Debugf("New stream from %s", pid.Pretty()) + + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + w := ggio.NewDelimitedWriter(s) + + for { + var req pb.Message + var res pb.Message + + err := r.ReadMsg(&req) + if err != nil { + s.Reset() + return + } + + t := req.GetType() + switch t { + case pb.Message_REGISTER: + r := rz.handleRegister(pid, req.GetRegister()) + res.Type = pb.Message_REGISTER_RESPONSE.Enum() + res.RegisterResponse = r + err = w.WriteMsg(&res) + if err != nil { + log.Debugf("Error writing response: %s", err.Error()) + s.Reset() + return + } + + case pb.Message_UNREGISTER: + err := rz.handleUnregister(pid, req.GetUnregister()) + if err != nil { + log.Debugf("Error unregistering peer: %s", err.Error()) + } + + case pb.Message_DISCOVER: + r := rz.handleDiscover(pid, req.GetDiscover()) + res.Type = pb.Message_DISCOVER_RESPONSE.Enum() + res.DiscoverResponse = r + err = w.WriteMsg(&res) + if err != nil { + log.Debugf("Error writing response: %s", err.Error()) + s.Reset() + return + } + + default: + log.Debugf("Unexpected message: %s", t.String()) + s.Reset() + return + } + } +} + +func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) *pb.Message_RegisterResponse { + ns := m.GetNs() + if ns == "" { + return newRegisterResponseError(pb.Message_E_INVALID_NAMESPACE, "unspecified namespace") + } + + if len(ns) > MaxNamespaceLength { + return newRegisterResponseError(pb.Message_E_INVALID_NAMESPACE, "namespace too long") + } + + mpi := m.GetPeer() + if mpi == nil { + return newRegisterResponseError(pb.Message_E_INVALID_PEER_INFO, "missing peer info") + } + + mpid := mpi.GetId() + if mpid != nil { + mp, err := peer.IDFromBytes(mpid) + if err != nil { + return newRegisterResponseError(pb.Message_E_INVALID_PEER_INFO, "bad peer id") + } + + if mp != p { + return newRegisterResponseError(pb.Message_E_INVALID_PEER_INFO, "peer id mismatch") + } + } + + maddrs := mpi.GetAddrs() + if len(maddrs) == 0 { + return newRegisterResponseError(pb.Message_E_INVALID_PEER_INFO, "missing peer addresses") + } + + mlen := 0 + for _, maddr := range maddrs { + mlen += len(maddr) + } + if mlen > MaxPeerAddressLength { + return newRegisterResponseError(pb.Message_E_INVALID_PEER_INFO, "peer info too long") + } + + // Note: + // We don't validate the addresses, because they could include protocols we don't understand + // Perhaps we should though. + + mttl := m.GetTtl() + if mttl < 0 || mttl > MaxTTL { + return newRegisterResponseError(pb.Message_E_INVALID_TTL, "bad ttl") + } + + ttl := DefaultTTL + if mttl > 0 { + ttl = int(mttl) + } + + // now check how many registrations we have for this peer -- simple limit to defend + // against trivial DoS attacks (eg a peer connects and keeps registering until it + // fills our db) + rcount, err := rz.DB.CountRegistrations(p) + if err != nil { + log.Errorf("Error counting registrations: %s", err.Error()) + return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + } + + if rcount > MaxRegistrations { + return newRegisterResponseError(pb.Message_E_NOT_AUTHORIZED, "too many registrations") + } + + // ok, seems like we can register + err = rz.DB.Register(p, ns, maddrs, ttl) + if err != nil { + log.Errorf("Error registering: %s", err.Error()) + return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + } + + return newRegisterResponse() +} + +func (rz *RendezvousService) handleUnregister(p peer.ID, m *pb.Message_Unregister) error { + ns := m.GetNs() + + mpid := m.GetId() + if mpid != nil { + mp, err := peer.IDFromBytes(mpid) + if err != nil { + return err + } + + if mp != p { + return fmt.Errorf("peer id mismatch: %s asked to unregister %s", p.Pretty(), mp.Pretty()) + } + } + + return rz.DB.Unregister(p, ns) +} + +func (rz *RendezvousService) handleDiscover(p peer.ID, m *pb.Message_Discover) *pb.Message_DiscoverResponse { + ns := m.GetNs() + + if len(ns) > MaxNamespaceLength { + return newDiscoverResponseError(pb.Message_E_INVALID_NAMESPACE, "namespace too long") + } + + limit := MaxDiscoverLimit + mlimit := m.GetLimit() + if mlimit > 0 && mlimit < int64(limit) { + limit = int(mlimit) + } + + cookie := m.GetCookie() + if cookie != nil && !rz.DB.ValidCookie(ns, cookie) { + return newDiscoverResponseError(pb.Message_E_INVALID_COOKIE, "bad cookie") + } + + regs, cookie, err := rz.DB.Discover(ns, cookie, limit) + if err != nil { + log.Errorf("Error in query: %s", err.Error()) + return newDiscoverResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + } + + return newDiscoverResponse(regs, cookie) +} From dbe6b0ddb5485168a3331f753cb5a6eb0cdcbd6b Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 12:05:18 +0300 Subject: [PATCH 16/47] rendezvous service sync: hook for federation --- svc.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/svc.go b/svc.go index 71b609a..7cc02e7 100644 --- a/svc.go +++ b/svc.go @@ -21,16 +21,22 @@ const ( ) type RendezvousService struct { - DB *DB + DB *DB + rzs []RendezvousSync } -func NewRendezvousService(ctx context.Context, host host.Host, dbpath string) (*RendezvousService, error) { +type RendezvousSync interface { + Register(p peer.ID, ns string, addrs [][]byte, ttl int) + Unregister(p peer.ID, ns string) +} + +func NewRendezvousService(ctx context.Context, host host.Host, dbpath string, rzs ...RendezvousSync) (*RendezvousService, error) { db, err := OpenDB(ctx, dbpath) if err != nil { return nil, err } - rz := &RendezvousService{DB: db} + rz := &RendezvousService{DB: db, rzs: rzs} host.SetStreamHandler(RendezvousProto, rz.handleStream) return rz, nil } @@ -164,6 +170,10 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) } + for _, rzs := range rz.rzs { + rzs.Register(p, ns, maddrs, ttl) + } + return newRegisterResponse() } @@ -182,7 +192,16 @@ func (rz *RendezvousService) handleUnregister(p peer.ID, m *pb.Message_Unregiste } } - return rz.DB.Unregister(p, ns) + err := rz.DB.Unregister(p, ns) + if err != nil { + return err + } + + for _, rzs := range rz.rzs { + rzs.Unregister(p, ns) + } + + return nil } func (rz *RendezvousService) handleDiscover(p peer.ID, m *pb.Message_Discover) *pb.Message_DiscoverResponse { From 6c1d28214b5ed9d249d64c8602ffc30a2c175f2a Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 13:25:18 +0300 Subject: [PATCH 17/47] Registration records should have an actual peer ID --- proto.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proto.go b/proto.go index f1c48d6..c1f004e 100644 --- a/proto.go +++ b/proto.go @@ -22,7 +22,7 @@ const ( ) type RegistrationRecord struct { - Id []byte + Id peer.ID Addrs [][]byte Ns string Ttl int @@ -130,7 +130,7 @@ func newDiscoverResponse(regs []RegistrationRecord, cookie []byte) *pb.Message_D rns := reg.Ns rreg.Ns = &rns rreg.Peer = new(pb.Message_PeerInfo) - rreg.Peer.Id = reg.Id + rreg.Peer.Id = []byte(reg.Id) rreg.Peer.Addrs = reg.Addrs rttl := int64(reg.Ttl) rreg.Ttl = &rttl From 8181424229952805c74f29d2920b42a5e12a1067 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 13:29:19 +0300 Subject: [PATCH 18/47] client: use larger batch in discovery, only poll immediately if full --- client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client.go b/client.go index 99995be..ca19cf1 100644 --- a/client.go +++ b/client.go @@ -180,7 +180,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) - const batch = 100 + const batch = 200 var ( cookie []byte @@ -203,7 +203,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist } } - if len(regs) < batch/2 { + if len(regs) < batch { select { case <-time.After(2 * time.Minute): case <-ctx.Done(): From fbaf21c098056a7fd745a54620b259e2ff0d863e Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 13:38:34 +0300 Subject: [PATCH 19/47] client: add TODO comment for adaptive backoff --- client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client.go b/client.go index ca19cf1..8a42219 100644 --- a/client.go +++ b/client.go @@ -204,6 +204,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist } if len(regs) < batch { + // TODO adaptive backoff for heavily loaded rendezvous points select { case <-time.After(2 * time.Minute): case <-ctx.Done(): From 4e3eaa7ba072352b728b47b9959bc51ef08804dd Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 14:44:14 +0300 Subject: [PATCH 20/47] refactor service constructor into two parts --- svc.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/svc.go b/svc.go index 7cc02e7..2b368ae 100644 --- a/svc.go +++ b/svc.go @@ -36,9 +36,14 @@ func NewRendezvousService(ctx context.Context, host host.Host, dbpath string, rz return nil, err } + rz := NewRendezvousServiceWithDB(host, db, rzs...) + return rz, nil +} + +func NewRendezvousServiceWithDB(host host.Host, db *DB, rzs ...RendezvousSync) *RendezvousService { rz := &RendezvousService{DB: db, rzs: rzs} host.SetStreamHandler(RendezvousProto, rz.handleStream) - return rz, nil + return rz } func (rz *RendezvousService) handleStream(s inet.Stream) { From aa3f46c89786ab8d79f0213731cc980b1838a051 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 14:50:46 +0300 Subject: [PATCH 21/47] user parameter for ttl in Register --- client.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/client.go b/client.go index 8a42219..b20c31a 100644 --- a/client.go +++ b/client.go @@ -73,27 +73,31 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { return nil } -func Register(ctx context.Context, rz Rendezvous, ns string) error { - err := rz.Register(ctx, ns, DefaultTTL) +func Register(ctx context.Context, rz Rendezvous, ns string, ttl int) error { + if ttl < 120 { + return fmt.Errorf("registration TTL is too short") + } + + err := rz.Register(ctx, ns, ttl) if err != nil { return err } - go registerRefresh(ctx, rz, ns) + go registerRefresh(ctx, rz, ns, ttl) return nil } -func registerRefresh(ctx context.Context, rz Rendezvous, ns string) { - const refresh = DefaultTTL - 30 +func registerRefresh(ctx context.Context, rz Rendezvous, ns string, ttl int) { + refresh := time.Duration(ttl-30) * time.Second for { select { - case <-time.After(refresh * time.Second): + case <-time.After(refresh): case <-ctx.Done(): return } - err := rz.Register(ctx, ns, DefaultTTL) + err := rz.Register(ctx, ns, ttl) if err != nil { log.Errorf("Error registering [%s]: %s", ns, err.Error()) } From c703d37aa2036ed6609a41b1e58af4d1de433804 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 23 Apr 2018 22:28:16 +0300 Subject: [PATCH 22/47] database logic implementation --- db.go | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 338 insertions(+), 8 deletions(-) diff --git a/db.go b/db.go index cfee9cb..117445d 100644 --- a/db.go +++ b/db.go @@ -2,34 +2,364 @@ package rendezvous import ( "context" + "crypto/rand" + "database/sql" "errors" + "os" + "time" + + _ "github.com/mattn/go-sqlite3" peer "github.com/libp2p/go-libp2p-peer" ) type DB struct { + db *sql.DB + + insertPeerRegistration *sql.Stmt + deletePeerRegistrations *sql.Stmt + deletePeerRegistrationsNs *sql.Stmt + countPeerRegistrations *sql.Stmt + selectPeerRegistrations *sql.Stmt + selectPeerRegistrationsNS *sql.Stmt + selectPeerRegistrationsC *sql.Stmt + selectPeerRegistrationsNSC *sql.Stmt + deleteExpiredRegistrations *sql.Stmt + + nonce []byte + + cancel func() } func OpenDB(ctx context.Context, path string) (*DB, error) { - return nil, errors.New("IMPLEMENTME: OpenDB") + var create bool + if path == ":memory:" { + create = true + } else { + _, err := os.Stat(path) + switch { + case os.IsNotExist(err): + create = true + case err != nil: + return nil, err + } + } + + db, err := sql.Open("sqlite3", path) + if err != nil { + return nil, err + } + + rdb := &DB{db: db} + if create { + err = rdb.prepareDB() + if err != nil { + db.Close() + return nil, err + } + } else { + err = rdb.loadNonce() + if err != nil { + db.Close() + return nil, err + } + } + + err = rdb.prepareStmts() + if err != nil { + db.Close() + return nil, err + } + + bgctx, cancel := context.WithCancel(ctx) + rdb.cancel = cancel + go rdb.background(bgctx) + + return rdb, nil +} + +func (db *DB) Close() error { + db.cancel() + return db.db.Close() +} + +func (db *DB) prepareDB() error { + _, err := db.db.Exec("CREATE TABLE Registrations (counter INTEGER PRIMARY KEY AUTOINCREMENT, peer VARCHAR(64), ns VARCHAR, expire INTEGER, addrs VARBINARY)") + if err != nil { + return err + } + + _, err = db.db.Exec("CREATE TABLE Nonce (nonce VARBINARY)") + if err != nil { + return err + } + + nonce := make([]byte, 16) + _, err = rand.Read(nonce) + if err != nil { + return err + } + + _, err = db.db.Exec("INSERT INTO Nonce VALUES (?)", nonce) + if err != nil { + return err + } + + db.nonce = nonce + return nil +} + +func (db *DB) loadNonce() error { + var nonce []byte + row := db.db.QueryRow("SELECT nonce FROM Nonce") + err := row.Scan(&nonce) + if err != nil { + return err + } + + db.nonce = nonce + return nil +} + +func (db *DB) prepareStmts() error { + stmt, err := db.db.Prepare("INSERT INTO Registrations VALUES (NULL, ?, ?, ?, ?)") + if err != nil { + return err + } + db.insertPeerRegistration = stmt + + stmt, err = db.db.Prepare("DELETE FROM Registrations WHERE peer = ?") + if err != nil { + return err + } + db.deletePeerRegistrations = stmt + + stmt, err = db.db.Prepare("DELETE FROM Registrations WHERE peer = ? AND ns = ?") + if err != nil { + return err + } + db.deletePeerRegistrationsNs = stmt + + stmt, err = db.db.Prepare("SELECT COUNT(*) FROM Registrations WHERE peer = ?") + if err != nil { + return err + } + db.countPeerRegistrations = stmt + + stmt, err = db.db.Prepare("SELECT * FROM Registrations WHERE expire > ? LIMIT ?") + if err != nil { + return err + } + db.selectPeerRegistrations = stmt + + stmt, err = db.db.Prepare("SELECT * FROM Registrations WHERE ns = ? AND expire > ? LIMIT ?") + if err != nil { + return err + } + db.selectPeerRegistrationsNS = stmt + + stmt, err = db.db.Prepare("SELECT * FROM Registrations WHERE counter > ? AND expire > ? LIMIT ?") + if err != nil { + return err + } + db.selectPeerRegistrationsC = stmt + + stmt, err = db.db.Prepare("SELECT * FROM Registrations WHERE counter > ? AND ns = ? AND expire > ? LIMIT ?") + if err != nil { + return err + } + db.selectPeerRegistrationsNSC = stmt + + stmt, err = db.db.Prepare("DELETE FROM Registrations WHERE expire < ?") + if err != nil { + return err + } + db.deleteExpiredRegistrations = stmt + + return nil } func (db *DB) Register(p peer.ID, ns string, addrs [][]byte, ttl int) error { - return errors.New("IMPLEMENTME: DB.Register") + pid := p.Pretty() + maddrs := packAddrs(addrs) + expire := time.Now().Unix() + int64(ttl) + + tx, err := db.db.Begin() + if err != nil { + return err + } + + delOld := tx.Stmt(db.deletePeerRegistrationsNs) + insertNew := tx.Stmt(db.insertPeerRegistration) + + _, err = delOld.Exec(pid, ns) + if err != nil { + tx.Rollback() + return err + } + + _, err = insertNew.Exec(pid, ns, expire, maddrs) + if err != nil { + tx.Rollback() + return err + } + + return tx.Commit() } func (db *DB) CountRegistrations(p peer.ID) (int, error) { - return 0, errors.New("IMPLEMENTME: DB.CountRegistrations") + pid := p.Pretty() + + row := db.countPeerRegistrations.QueryRow(pid) + + var count int + err := row.Scan(&count) + + return count, err } func (db *DB) Unregister(p peer.ID, ns string) error { - return errors.New("IMPLEMENTME: DB.Unregister") -} + pid := p.Pretty() -func (db *DB) ValidCookie(ns string, cookie []byte) bool { - return false + var err error + + if ns == "" { + _, err = db.deletePeerRegistrations.Exec(pid) + } else { + _, err = db.deletePeerRegistrationsNs.Exec(pid, ns) + } + + return err } func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecord, []byte, error) { - return nil, nil, errors.New("IMPLEMENTME: DB.Discover") + now := time.Now().Unix() + + var ( + counter int64 + rows *sql.Rows + err error + ) + + if cookie != nil { + counter, err = cookieToCounter(cookie) + if err != nil { + log.Errorf("error unpacking cookie: %s", err.Error()) + return nil, nil, err + } + } + + if counter > 0 { + if ns == "" { + rows, err = db.selectPeerRegistrationsC.Query(counter, now, limit) + } else { + rows, err = db.selectPeerRegistrationsNSC.Query(counter, ns, now, limit) + } + } else { + if ns == "" { + rows, err = db.selectPeerRegistrations.Query(now, limit) + } else { + rows, err = db.selectPeerRegistrations.Query(ns, now, limit) + } + } + + if err != nil { + log.Errorf("query error: %s", err.Error()) + return nil, nil, err + } + + defer rows.Close() + + regs := make([]RegistrationRecord, 0, limit) + for rows.Next() { + var ( + reg RegistrationRecord + rid string + rns string + expire int64 + raddrs []byte + addrs [][]byte + p peer.ID + ) + + err = rows.Scan(&counter, &rid, &rns, &expire, &raddrs) + if err != nil { + log.Errorf("row scan error: %s", err.Error()) + return nil, nil, err + } + + p, err = peer.IDB58Decode(rid) + if err != nil { + log.Errorf("error decoding peer id: %s", err.Error()) + continue + } + reg.Id = p + + addrs, err = unpackAddrs(raddrs) + if err != nil { + log.Errorf("error unpacking address: %s", err.Error()) + continue + } + reg.Addrs = addrs + + reg.Ttl = int(expire - now) + + if ns == "" { + reg.Ns = rns + } + + regs = append(regs, reg) + } + + err = rows.Err() + if err != nil { + return nil, nil, err + } + + if counter > 0 { + cookie = counterToCookie(counter, ns, db.nonce) + } + + return regs, cookie, nil +} + +func (db *DB) ValidCookie(ns string, cookie []byte) bool { + // XXX + return false +} + +func (db *DB) background(ctx context.Context) { + for { + now := time.Now().Unix() + _, err := db.deleteExpiredRegistrations.Exec(now) + if err != nil { + log.Errorf("error deleting expired registrations: %s", err.Error()) + } + + select { + case <-time.After(15 * time.Minute): + case <-ctx.Done(): + return + } + } +} + +func packAddrs(addrs [][]byte) []byte { + // XXX + return nil +} + +func unpackAddrs(maddrs []byte) ([][]byte, error) { + // XXX + return nil, errors.New("IMPLEMENTME: unpackAddrs") +} + +func cookieToCounter(cookie []byte) (int64, error) { + // XXX + return 0, errors.New("IMPLEMENTME: cookieToCounter") +} + +func counterToCookie(counter int64, ns string, nonce []byte) []byte { + // XXX + return nil } From ae10cc6b9ffdcdcf910a5f476c7201fe9ddbabba Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 12:00:37 +0300 Subject: [PATCH 23/47] implement binary packing details --- db.go | 116 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 19 deletions(-) diff --git a/db.go b/db.go index 117445d..dc3786e 100644 --- a/db.go +++ b/db.go @@ -1,10 +1,13 @@ package rendezvous import ( + "bytes" "context" "crypto/rand" + "crypto/sha256" "database/sql" - "errors" + "encoding/binary" + "fmt" "os" "time" @@ -242,7 +245,7 @@ func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecor ) if cookie != nil { - counter, err = cookieToCounter(cookie) + counter, err = unpackCookie(cookie) if err != nil { log.Errorf("error unpacking cookie: %s", err.Error()) return nil, nil, err @@ -293,15 +296,15 @@ func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecor log.Errorf("error decoding peer id: %s", err.Error()) continue } - reg.Id = p - addrs, err = unpackAddrs(raddrs) + addrs, err := unpackAddrs(raddrs) if err != nil { log.Errorf("error unpacking address: %s", err.Error()) continue } - reg.Addrs = addrs + reg.Id = p + reg.Addrs = addrs reg.Ttl = int(expire - now) if ns == "" { @@ -317,15 +320,14 @@ func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecor } if counter > 0 { - cookie = counterToCookie(counter, ns, db.nonce) + cookie = packCookie(counter, ns, db.nonce) } return regs, cookie, nil } func (db *DB) ValidCookie(ns string, cookie []byte) bool { - // XXX - return false + return validCookie(cookie, ns, db.nonce) } func (db *DB) background(ctx context.Context) { @@ -345,21 +347,97 @@ func (db *DB) background(ctx context.Context) { } func packAddrs(addrs [][]byte) []byte { - // XXX - return nil + packlen := 0 + for _, addr := range addrs { + packlen = packlen + 2 + len(addr) + } + + packed := make([]byte, packlen) + buf := packed + for _, addr := range addrs { + binary.BigEndian.PutUint16(buf, uint16(len(addr))) + buf = buf[2:] + copy(buf, addr) + buf = buf[len(addr):] + } + + return packed } -func unpackAddrs(maddrs []byte) ([][]byte, error) { - // XXX - return nil, errors.New("IMPLEMENTME: unpackAddrs") +func unpackAddrs(packed []byte) ([][]byte, error) { + var addrs [][]byte + + buf := packed + for len(buf) > 1 { + l := binary.BigEndian.Uint16(buf) + buf = buf[2:] + if len(buf) < int(l) { + return nil, fmt.Errorf("bad packed address: not enough bytes %v %v", packed, buf) + } + addr := make([]byte, l) + copy(addr, buf[:l]) + buf = buf[l:] + addrs = append(addrs, addr) + } + + if len(buf) > 0 { + return nil, fmt.Errorf("bad packed address: unprocessed bytes: %v %v", packed, buf) + } + + return addrs, nil } -func cookieToCounter(cookie []byte) (int64, error) { - // XXX - return 0, errors.New("IMPLEMENTME: cookieToCounter") +// cookie: counter:SHA256(nonce + ns + counter) +func packCookie(counter int64, ns string, nonce []byte) []byte { + cbits := make([]byte, 8) + binary.BigEndian.PutUint64(cbits, uint64(counter)) + + hash := sha256.New() + _, err := hash.Write(nonce) + if err != nil { + panic(err) + } + _, err = hash.Write([]byte(ns)) + if err != nil { + panic(err) + } + _, err = hash.Write(cbits) + if err != nil { + panic(err) + } + + return hash.Sum(cbits) } -func counterToCookie(counter int64, ns string, nonce []byte) []byte { - // XXX - return nil +func unpackCookie(cookie []byte) (int64, error) { + if len(cookie) < 8 { + return 0, fmt.Errorf("bad packed cookie: not enough bytes: %v", cookie) + } + + counter := binary.BigEndian.Uint64(cookie[:8]) + return int64(counter), nil +} + +func validCookie(cookie []byte, ns string, nonce []byte) bool { + if len(cookie) != 40 { + return false + } + + cbits := cookie[:8] + hash := sha256.New() + _, err := hash.Write(nonce) + if err != nil { + panic(err) + } + _, err = hash.Write([]byte(ns)) + if err != nil { + panic(err) + } + _, err = hash.Write(cbits) + if err != nil { + panic(err) + } + hbits := hash.Sum(nil) + + return bytes.Equal(cookie[8:], hbits) } From 8c1227209a7c49e6712f3203bd095ab536324915 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 12:00:53 +0300 Subject: [PATCH 24/47] better logging for service i/o --- svc.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/svc.go b/svc.go index 2b368ae..5261825 100644 --- a/svc.go +++ b/svc.go @@ -175,6 +175,8 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) } + log.Infof("registered peer %s %s (%d)", p, ns, ttl) + for _, rzs := range rz.rzs { rzs.Register(p, ns, maddrs, ttl) } @@ -202,6 +204,8 @@ func (rz *RendezvousService) handleUnregister(p peer.ID, m *pb.Message_Unregiste return err } + log.Infof("unregistered peer %s %s", p, ns) + for _, rzs := range rz.rzs { rzs.Unregister(p, ns) } @@ -233,5 +237,7 @@ func (rz *RendezvousService) handleDiscover(p peer.ID, m *pb.Message_Discover) * return newDiscoverResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) } + log.Infof("discover query: %s %s -> %d", p, ns, len(regs)) + return newDiscoverResponse(regs, cookie) } From 53dfbc7ae159df6c601eda939133a06ddd3598bb Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 12:34:39 +0300 Subject: [PATCH 25/47] test address and cookie packing --- db_test.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 db_test.go diff --git a/db_test.go b/db_test.go new file mode 100644 index 0000000..f65949c --- /dev/null +++ b/db_test.go @@ -0,0 +1,56 @@ +package rendezvous + +import ( + "bytes" + "math/rand" + "testing" +) + +func TestPackAddrs(t *testing.T) { + addrs := make([][]byte, 5) + for i := 0; i < 5; i++ { + addrs[i] = make([]byte, rand.Intn(256)) + } + + packed := packAddrs(addrs) + unpacked, err := unpackAddrs(packed) + if err != nil { + t.Fatal(err) + } + + if len(addrs) != len(unpacked) { + t.Fatal("unpacked address length mismatch") + } + + for i, addr := range addrs { + if !bytes.Equal(addr, unpacked[i]) { + t.Fatal("unpacked addr not equal to original") + } + } +} + +func TestPackCookie(t *testing.T) { + nonce := make([]byte, 16) + _, err := rand.Read(nonce) + if err != nil { + t.Fatal(err) + } + + counter := rand.Int63() + ns := "blah" + + cookie := packCookie(counter, ns, nonce) + + if !validCookie(cookie, ns, nonce) { + t.Fatal("packed an invalid cookie") + } + + xcounter, err := unpackCookie(cookie) + if err != nil { + t.Fatal(err) + } + + if counter != xcounter { + t.Fatal("unpacked cookie counter not equal to original") + } +} From f41fbba29afcb394cdefe223748e1707c229580e Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 14:08:17 +0300 Subject: [PATCH 26/47] test db functionality --- db.go | 21 ++-- db_test.go | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 309 insertions(+), 11 deletions(-) diff --git a/db.go b/db.go index dc3786e..1ca3d7e 100644 --- a/db.go +++ b/db.go @@ -53,6 +53,11 @@ func OpenDB(ctx context.Context, path string) (*DB, error) { return nil, err } + if path == ":memory:" { + // this is necessary to avoid creating a new database on each connection + db.SetMaxOpenConns(1) + } + rdb := &DB{db: db} if create { err = rdb.prepareDB() @@ -262,7 +267,7 @@ func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecor if ns == "" { rows, err = db.selectPeerRegistrations.Query(now, limit) } else { - rows, err = db.selectPeerRegistrations.Query(ns, now, limit) + rows, err = db.selectPeerRegistrationsNS.Query(ns, now, limit) } } @@ -332,11 +337,7 @@ func (db *DB) ValidCookie(ns string, cookie []byte) bool { func (db *DB) background(ctx context.Context) { for { - now := time.Now().Unix() - _, err := db.deleteExpiredRegistrations.Exec(now) - if err != nil { - log.Errorf("error deleting expired registrations: %s", err.Error()) - } + db.cleanupExpired() select { case <-time.After(15 * time.Minute): @@ -346,6 +347,14 @@ func (db *DB) background(ctx context.Context) { } } +func (db *DB) cleanupExpired() { + now := time.Now().Unix() + _, err := db.deleteExpiredRegistrations.Exec(now) + if err != nil { + log.Errorf("error deleting expired registrations: %s", err.Error()) + } +} + func packAddrs(addrs [][]byte) []byte { packlen := 0 for _, addr := range addrs { diff --git a/db_test.go b/db_test.go index f65949c..f28c1fa 100644 --- a/db_test.go +++ b/db_test.go @@ -2,8 +2,13 @@ package rendezvous import ( "bytes" + "context" "math/rand" "testing" + "time" + + peer "github.com/libp2p/go-libp2p-peer" + ma "github.com/multiformats/go-multiaddr" ) func TestPackAddrs(t *testing.T) { @@ -18,15 +23,24 @@ func TestPackAddrs(t *testing.T) { t.Fatal(err) } - if len(addrs) != len(unpacked) { - t.Fatal("unpacked address length mismatch") + if !equalAddrs(addrs, unpacked) { + t.Fatal("unpacked addr not equal to original") + } +} + +func equalAddrs(addrs1, addrs2 [][]byte) bool { + if len(addrs1) != len(addrs2) { + return false } - for i, addr := range addrs { - if !bytes.Equal(addr, unpacked[i]) { - t.Fatal("unpacked addr not equal to original") + for i, addr1 := range addrs1 { + addr2 := addrs2[i] + if !bytes.Equal(addr1, addr2) { + return false } } + + return true } func TestPackCookie(t *testing.T) { @@ -54,3 +68,278 @@ func TestPackCookie(t *testing.T) { t.Fatal("unpacked cookie counter not equal to original") } } + +func TestOpenCloseMemDB(t *testing.T) { + db, err := OpenDB(context.Background(), ":memory:") + if err != nil { + t.Fatal(err) + } + + // let the flush goroutine run its cleanup act + time.Sleep(1 * time.Second) + + err = db.Close() + if err != nil { + t.Fatal(err) + } +} + +func TestOpenCloseFSDB(t *testing.T) { + db, err := OpenDB(context.Background(), "/tmp/rendezvous-test.db") + if err != nil { + t.Fatal(err) + } + + nonce1 := db.nonce + + // let the flush goroutine run its cleanup act + time.Sleep(1 * time.Second) + + err = db.Close() + if err != nil { + t.Fatal(err) + } + + db, err = OpenDB(context.Background(), "/tmp/rendezvous-test.db") + if err != nil { + t.Fatal(err) + } + + nonce2 := db.nonce + + // let the flush goroutine run its cleanup act + time.Sleep(1 * time.Second) + + err = db.Close() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(nonce1, nonce2) { + t.Fatal("persistent db nonces are not equal") + } +} + +func TestDBRegistrationAndDiscovery(t *testing.T) { + db, err := OpenDB(context.Background(), ":memory:") + if err != nil { + t.Fatal(err) + } + + p1, err := peer.IDB58Decode("QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH") + if err != nil { + t.Fatal(err) + } + + p2, err := peer.IDB58Decode("QmUkUQgxXeggyaD5Ckv8ZqfW8wHBX6cYyeiyqvVZYzq5Bi") + if err != nil { + t.Fatal(err) + } + + addr1, err := ma.NewMultiaddr("/ip4/1.1.1.1/tcp/9999") + if err != nil { + t.Fatal(err) + } + addrs1 := [][]byte{addr1.Bytes()} + + addr2, err := ma.NewMultiaddr("/ip4/2.2.2.2/tcp/9999") + if err != nil { + t.Fatal(err) + } + addrs2 := [][]byte{addr2.Bytes()} + + // register p1 and do discovery + err = db.Register(p1, "foo1", addrs1, 60) + if err != nil { + t.Fatal(err) + } + + count, err := db.CountRegistrations(p1) + if err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatal("registrations for p1 should be 1") + } + + rrs, cookie, err := db.Discover("foo1", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("should have got 1 registration") + } + rr := rrs[0] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + // register p2 and do progressive discovery + err = db.Register(p2, "foo1", addrs2, 60) + if err != nil { + t.Fatal(err) + } + + count, err = db.CountRegistrations(p2) + if err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatal("registrations for p2 should be 1") + } + + rrs, cookie, err = db.Discover("foo1", cookie, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("should have got 1 registration") + } + rr = rrs[0] + if rr.Id != p2 { + t.Fatal("expected p2 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs2) { + t.Fatal("expected p2's addrs in registration") + } + + // reregister p1 and do progressive discovery + err = db.Register(p1, "foo1", addrs1, 60) + if err != nil { + t.Fatal(err) + } + + count, err = db.CountRegistrations(p1) + if err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatal("registrations for p1 should be 1") + } + + rrs, cookie, err = db.Discover("foo1", cookie, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("should have got 1 registration") + } + rr = rrs[0] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + // do a full discovery + rrs, _, err = db.Discover("foo1", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 2 { + t.Fatal("should have got 2 registration") + } + rr = rrs[0] + if rr.Id != p2 { + t.Fatal("expected p2 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs2) { + t.Fatal("expected p2's addrs in registration") + } + + rr = rrs[1] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + // unregister p2 and redo discovery + err = db.Unregister(p2, "foo1") + if err != nil { + t.Fatal(err) + } + + count, err = db.CountRegistrations(p2) + if err != nil { + t.Fatal(err) + } + if count != 0 { + t.Fatal("registrations for p2 should be 0") + } + + rrs, _, err = db.Discover("foo1", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("should have got 1 registration") + } + rr = rrs[0] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + db.Close() +} + +func TestDBCleanup(t *testing.T) { + db, err := OpenDB(context.Background(), ":memory:") + if err != nil { + t.Fatal(err) + } + + p1, err := peer.IDB58Decode("QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH") + if err != nil { + t.Fatal(err) + } + + addr1, err := ma.NewMultiaddr("/ip4/1.1.1.1/tcp/9999") + if err != nil { + t.Fatal(err) + } + addrs1 := [][]byte{addr1.Bytes()} + + err = db.Register(p1, "foo1", addrs1, 1) + if err != nil { + t.Fatal(err) + } + + count, err := db.CountRegistrations(p1) + if err != nil { + t.Fatal(err) + } + if count != 1 { + t.Fatal("registrations for p1 should be 1") + } + + time.Sleep(2 * time.Second) + + db.cleanupExpired() + + count, err = db.CountRegistrations(p1) + if err != nil { + t.Fatal(err) + } + if count != 0 { + t.Fatal("registrations for p1 should be 0") + } + + rrs, _, err := db.Discover("foo1", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 0 { + t.Fatal("should have got 0 registrations") + } + + db.Close() +} From cfbcddee4195f8822647b4ece0375da2ffd150b1 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 14:10:50 +0300 Subject: [PATCH 27/47] up MaxRegistrations to 1k --- svc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/svc.go b/svc.go index 5261825..bd7ef82 100644 --- a/svc.go +++ b/svc.go @@ -16,7 +16,7 @@ const ( MaxTTL = 72 * 3600 // 72hr MaxNamespaceLength = 256 MaxPeerAddressLength = 2048 - MaxRegistrations = 100 + MaxRegistrations = 1000 MaxDiscoverLimit = 1000 ) From 4788ef758e309e76a9cbba7aa4a5c99247bbf9c3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 15:53:22 +0300 Subject: [PATCH 28/47] test db functionality with multiple namespaces --- db_test.go | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/db_test.go b/db_test.go index f28c1fa..c5b192e 100644 --- a/db_test.go +++ b/db_test.go @@ -291,6 +291,173 @@ func TestDBRegistrationAndDiscovery(t *testing.T) { db.Close() } +func TestDBRegistrationAndDiscoveryMultipleNS(t *testing.T) { + db, err := OpenDB(context.Background(), ":memory:") + if err != nil { + t.Fatal(err) + } + + p1, err := peer.IDB58Decode("QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH") + if err != nil { + t.Fatal(err) + } + + p2, err := peer.IDB58Decode("QmUkUQgxXeggyaD5Ckv8ZqfW8wHBX6cYyeiyqvVZYzq5Bi") + if err != nil { + t.Fatal(err) + } + + addr1, err := ma.NewMultiaddr("/ip4/1.1.1.1/tcp/9999") + if err != nil { + t.Fatal(err) + } + addrs1 := [][]byte{addr1.Bytes()} + + addr2, err := ma.NewMultiaddr("/ip4/2.2.2.2/tcp/9999") + if err != nil { + t.Fatal(err) + } + addrs2 := [][]byte{addr2.Bytes()} + + err = db.Register(p1, "foo1", addrs1, 60) + if err != nil { + t.Fatal(err) + } + + err = db.Register(p1, "foo2", addrs1, 60) + if err != nil { + t.Fatal(err) + } + + count, err := db.CountRegistrations(p1) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Fatal("registrations for p1 should be 2") + } + + rrs, cookie, err := db.Discover("", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 2 { + t.Fatal("should have got 2 registrations") + } + rr := rrs[0] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if rr.Ns != "foo1" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + rr = rrs[1] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if rr.Ns != "foo2" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + err = db.Register(p2, "foo1", addrs2, 60) + if err != nil { + t.Fatal(err) + } + + err = db.Register(p2, "foo2", addrs2, 60) + if err != nil { + t.Fatal(err) + } + + count, err = db.CountRegistrations(p2) + if err != nil { + t.Fatal(err) + } + if count != 2 { + t.Fatal("registrations for p2 should be 2") + } + + rrs, cookie, err = db.Discover("", cookie, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 2 { + t.Fatal("should have got 2 registrations") + } + rr = rrs[0] + if rr.Id != p2 { + t.Fatal("expected p2 ID in registration") + } + if rr.Ns != "foo1" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs2) { + t.Fatal("expected p2's addrs in registration") + } + + rr = rrs[1] + if rr.Id != p2 { + t.Fatal("expected p2 ID in registration") + } + if rr.Ns != "foo2" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs2) { + t.Fatal("expected p2's addrs in registration") + } + + err = db.Unregister(p2, "") + if err != nil { + t.Fatal(err) + } + + count, err = db.CountRegistrations(p2) + if err != nil { + t.Fatal(err) + } + if count != 0 { + t.Fatal("registrations for p2 should be 0") + } + + rrs, _, err = db.Discover("", nil, 100) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 2 { + t.Fatal("should have got 2 registrations") + } + rr = rrs[0] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if rr.Ns != "foo1" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + rr = rrs[1] + if rr.Id != p1 { + t.Fatal("expected p1 ID in registration") + } + if rr.Ns != "foo2" { + t.Fatal("expected namespace foo1 in registration") + } + if !equalAddrs(rr.Addrs, addrs1) { + t.Fatal("expected p1's addrs in registration") + } + + db.Close() +} + func TestDBCleanup(t *testing.T) { db, err := OpenDB(context.Background(), ":memory:") if err != nil { From a47367d67a836188aac141169d65235a1162f3ac Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 17:05:05 +0300 Subject: [PATCH 29/47] basic service test --- package.json | 12 ++++ svc_test.go | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 svc_test.go diff --git a/package.json b/package.json index cf8f9f1..c925c9c 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,18 @@ "hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV", "name": "gogo-protobuf", "version": "0.0.0" + }, + { + "author": "whyrusleeping", + "hash": "Qmc64U41EEB4nPG7wxjEqFwKJajS2f8kk5q2TvUrQf78Xu", + "name": "go-libp2p-blankhost", + "version": "0.2.7" + }, + { + "author": "whyrusleeping", + "hash": "Qmb6BsZf6Y3kxffXMNTubGPF1w1bkHtpvhfYbmnwP3NQyw", + "name": "go-libp2p-netutil", + "version": "0.3.11" } ], "gxVersion": "0.12.1", diff --git a/svc_test.go b/svc_test.go new file mode 100644 index 0000000..662901f --- /dev/null +++ b/svc_test.go @@ -0,0 +1,156 @@ +package rendezvous + +import ( + "context" + "testing" + + bhost "github.com/libp2p/go-libp2p-blankhost" + host "github.com/libp2p/go-libp2p-host" + netutil "github.com/libp2p/go-libp2p-netutil" +) + +func getRendezvousHosts(t *testing.T, ctx context.Context, n int) []host.Host { + hosts := getNetHosts(t, ctx, n) + for i := 1; i < len(hosts); i++ { + connect(t, hosts[0], hosts[i]) + } + return hosts +} + +func getNetHosts(t *testing.T, ctx context.Context, n int) []host.Host { + var out []host.Host + + for i := 0; i < n; i++ { + netw := netutil.GenSwarmNetwork(t, ctx) + h := bhost.NewBlankHost(netw) + out = append(out, h) + } + + return out +} + +func connect(t *testing.T, a, b host.Host) { + pinfo := a.Peerstore().PeerInfo(a.ID()) + err := b.Connect(context.Background(), pinfo) + if err != nil { + t.Fatal(err) + } +} + +func getRendezvousClients(t *testing.T, hosts []host.Host) []Rendezvous { + clients := make([]Rendezvous, len(hosts)-1) + for i, host := range hosts[1:] { + clients[i] = NewRendezvousClient(host, hosts[0].ID()) + } + return clients +} + +func TestSVCRegistrationAndDiscovery(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts := getRendezvousHosts(t, ctx, 5) + + svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + + clients := getRendezvousClients(t, hosts) + + err = clients[0].Register(ctx, "foo1", 60) + if err != nil { + t.Fatal(err) + } + + rrs, cookie, err := clients[0].Discover(ctx, "foo1", 10, nil) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("Expected 1 registration") + } + checkHostRegistration(t, rrs[0], hosts[1]) + + for i, client := range clients[1:] { + err = client.Register(ctx, "foo1", 60) + if err != nil { + t.Fatal(err) + } + + rrs, cookie, err = clients[0].Discover(ctx, "foo1", 10, cookie) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 1 { + t.Fatal("Expected 1 registration") + } + checkHostRegistration(t, rrs[0], hosts[2+i]) + } + + for _, client := range clients[1:] { + rrs, _, err = client.Discover(ctx, "foo1", 10, nil) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 4 { + t.Fatal("Expected 4 registrations") + } + + for j, rr := range rrs { + checkHostRegistration(t, rr, hosts[1+j]) + } + } + + err = clients[0].Unregister(ctx, "foo1") + if err != nil { + t.Fatal(err) + } + + for _, client := range clients[0:] { + rrs, _, err = client.Discover(ctx, "foo1", 10, nil) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 3 { + t.Fatal("Expected 3 registrations") + } + + for j, rr := range rrs { + checkHostRegistration(t, rr, hosts[2+j]) + } + } + + err = clients[1].Unregister(ctx, "") + for _, client := range clients[0:] { + rrs, _, err = client.Discover(ctx, "foo1", 10, nil) + if err != nil { + t.Fatal(err) + } + if len(rrs) != 2 { + t.Fatal("Expected 2 registrations") + } + + for j, rr := range rrs { + checkHostRegistration(t, rr, hosts[3+j]) + } + } +} + +func checkHostRegistration(t *testing.T, rr Registration, host host.Host) { + if rr.Peer.ID != host.ID() { + t.Fatal("bad registration: peer ID doesn't match host ID") + } + addrs := host.Addrs() + raddrs := rr.Peer.Addrs + if len(addrs) != len(raddrs) { + t.Fatal("bad registration: peer address length mismatch") + } + for i, addr := range addrs { + raddr := raddrs[i] + if !addr.Equal(raddr) { + t.Fatal("bad registration: peer address mismatch") + } + } +} From 2b0995f842d41f4bc1d0a5aa2ffebcdc870967b0 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 18:16:44 +0300 Subject: [PATCH 30/47] test service errors --- svc.go | 1 + svc_test.go | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/svc.go b/svc.go index bd7ef82..14e2de6 100644 --- a/svc.go +++ b/svc.go @@ -165,6 +165,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * } if rcount > MaxRegistrations { + log.Warningf("Too many registrations for %s", p) return newRegisterResponseError(pb.Message_E_NOT_AUTHORIZED, "too many registrations") } diff --git a/svc_test.go b/svc_test.go index 662901f..c0631dc 100644 --- a/svc_test.go +++ b/svc_test.go @@ -2,11 +2,19 @@ package rendezvous import ( "context" + "fmt" + "math/rand" "testing" + pb "github.com/libp2p/go-libp2p-rendezvous/pb" + + ggio "github.com/gogo/protobuf/io" bhost "github.com/libp2p/go-libp2p-blankhost" host "github.com/libp2p/go-libp2p-host" + inet "github.com/libp2p/go-libp2p-net" netutil "github.com/libp2p/go-libp2p-netutil" + peer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" ) func getRendezvousHosts(t *testing.T, ctx context.Context, n int) []host.Host { @@ -154,3 +162,166 @@ func checkHostRegistration(t *testing.T, rr Registration, host host.Host) { } } } + +func TestSVCErrors(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts := getRendezvousHosts(t, ctx, 2) + + svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + + // testable registration errors + res, err := doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("", pstore.PeerInfo{}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_NAMESPACE { + t.Fatal("expected E_INVALID_NAMESPACE") + } + + badns := make([]byte, 2*MaxNamespaceLength) + rand.Read(badns) + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage(string(badns), pstore.PeerInfo{}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_NAMESPACE { + t.Fatal("expected E_INVALID_NAMESPACE") + } + + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_PEER_INFO { + t.Fatal("expected E_INVALID_PEER_INFO") + } + + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{ID: peer.ID("blah")}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_PEER_INFO { + t.Fatal("expected E_INVALID_PEER_INFO") + } + + p, err := peer.IDB58Decode("QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH") + if err != nil { + t.Fatal(err) + } + + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{ID: p}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_PEER_INFO { + t.Fatal("expected E_INVALID_PEER_INFO") + } + + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID()}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_PEER_INFO { + t.Fatal("expected E_INVALID_PEER_INFO") + } + + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 2*MaxTTL)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_INVALID_TTL { + t.Fatal("expected E_INVALID_TTL") + } + + // do MaxRegistrations + for i := 0; i < MaxRegistrations+1; i++ { + ns := fmt.Sprintf("foo%d", i) + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage(ns, pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_OK { + t.Fatal("expected OK") + } + } + // and now fail + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) + if err != nil { + t.Fatal(err) + } + if res.GetRegisterResponse().GetStatus() != pb.Message_E_NOT_AUTHORIZED { + t.Fatal("expected E_NOT_AUTHORIZED") + } + + // testable discovery errors + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newDiscoverMessage(string(badns), 0, nil)) + if err != nil { + t.Fatal(err) + } + if res.GetDiscoverResponse().GetStatus() != pb.Message_E_INVALID_NAMESPACE { + t.Fatal("expected E_INVALID_NAMESPACE") + } + + badcookie := make([]byte, 10) + rand.Read(badcookie) + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newDiscoverMessage("foo", 0, badcookie)) + if err != nil { + t.Fatal(err) + } + if res.GetDiscoverResponse().GetStatus() != pb.Message_E_INVALID_COOKIE { + t.Fatal("expected E_INVALID_COOKIE") + } + + badcookie = make([]byte, 40) + rand.Read(badcookie) + res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), + newDiscoverMessage("foo", 0, badcookie)) + if err != nil { + t.Fatal(err) + } + if res.GetDiscoverResponse().GetStatus() != pb.Message_E_INVALID_COOKIE { + t.Fatal("expected E_INVALID_COOKIE") + } + +} + +func doTestRequest(ctx context.Context, host host.Host, rp peer.ID, m *pb.Message) (*pb.Message, error) { + s, err := host.NewStream(ctx, rp, RendezvousProto) + if err != nil { + return nil, err + } + defer s.Close() + + r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) + w := ggio.NewDelimitedWriter(s) + + err = w.WriteMsg(m) + if err != nil { + return nil, err + } + + res := new(pb.Message) + err = r.ReadMsg(res) + if err != nil { + return nil, err + } + + return res, nil +} From 9ab12abbdecf7f5eaaabecd337c9570f13d1fc26 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 18:23:10 +0300 Subject: [PATCH 31/47] make db nonce 32 bytes --- db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db.go b/db.go index 1ca3d7e..0265d1f 100644 --- a/db.go +++ b/db.go @@ -102,7 +102,7 @@ func (db *DB) prepareDB() error { return err } - nonce := make([]byte, 16) + nonce := make([]byte, 32) _, err = rand.Read(nonce) if err != nil { return err From 6c4fda5295ed2f9ef26865c3b2ffbd762e6a1389 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 18:43:43 +0300 Subject: [PATCH 32/47] test client specific functionality --- client.go | 6 ++- client_test.go | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 client_test.go diff --git a/client.go b/client.go index b20c31a..6e4e0d4 100644 --- a/client.go +++ b/client.go @@ -14,6 +14,10 @@ import ( pstore "github.com/libp2p/go-libp2p-peerstore" ) +var ( + DiscoverAsyncInterval = 2 * time.Minute +) + type Rendezvous interface { Register(ctx context.Context, ns string, ttl int) error Unregister(ctx context.Context, ns string) error @@ -210,7 +214,7 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist if len(regs) < batch { // TODO adaptive backoff for heavily loaded rendezvous points select { - case <-time.After(2 * time.Minute): + case <-time.After(DiscoverAsyncInterval): case <-ctx.Done(): return } diff --git a/client_test.go b/client_test.go new file mode 100644 index 0000000..6182cf3 --- /dev/null +++ b/client_test.go @@ -0,0 +1,120 @@ +package rendezvous + +import ( + "context" + "testing" + "time" + + host "github.com/libp2p/go-libp2p-host" + pstore "github.com/libp2p/go-libp2p-peerstore" +) + +func TestClientRegistrationAndDiscovery(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts := getRendezvousHosts(t, ctx, 5) + + svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + + clients := getRendezvousClients(t, hosts) + + err = Register(ctx, clients[0], "foo1", DefaultTTL) + if err != nil { + t.Fatal(err) + } + + pi, cookie, err := DiscoverPeers(ctx, clients[0], "foo1", 0, nil) + if err != nil { + t.Fatal(err) + } + if len(pi) != 1 { + t.Fatal("Expected 1 peer") + } + checkPeerInfo(t, pi[0], hosts[1]) + + for i, client := range clients[1:] { + err = Register(ctx, client, "foo1", DefaultTTL) + if err != nil { + t.Fatal(err) + } + + pi, cookie, err = DiscoverPeers(ctx, clients[0], "foo1", 10, cookie) + if err != nil { + t.Fatal(err) + } + if len(pi) != 1 { + t.Fatal("Expected 1 peer") + } + checkPeerInfo(t, pi[0], hosts[2+i]) + } + + for _, client := range clients[1:] { + pi, _, err = DiscoverPeers(ctx, client, "foo1", 10, nil) + if err != nil { + t.Fatal(err) + } + if len(pi) != 4 { + t.Fatal("Expected 4 registrations") + } + + for j, p := range pi { + checkPeerInfo(t, p, hosts[1+j]) + } + } +} + +func TestClientRegistrationAndDiscoveryAsync(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + hosts := getRendezvousHosts(t, ctx, 5) + + svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + + clients := getRendezvousClients(t, hosts) + + DiscoverAsyncInterval = 1 * time.Second + + ch, err := DiscoverPeersAsync(ctx, clients[0], "foo1") + if err != nil { + t.Fatal(err) + } + + for i, client := range clients[0:] { + err = Register(ctx, client, "foo1", DefaultTTL) + if err != nil { + t.Fatal(err) + } + + pi := <-ch + checkPeerInfo(t, pi, hosts[1+i]) + } + + DiscoverAsyncInterval = 2 * time.Minute +} + +func checkPeerInfo(t *testing.T, pi pstore.PeerInfo, host host.Host) { + if pi.ID != host.ID() { + t.Fatal("bad registration: peer ID doesn't match host ID") + } + addrs := host.Addrs() + raddrs := pi.Addrs + if len(addrs) != len(raddrs) { + t.Fatal("bad registration: peer address length mismatch") + } + for i, addr := range addrs { + raddr := raddrs[i] + if !addr.Equal(raddr) { + t.Fatal("bad registration: peer address mismatch") + } + } +} From e5302041072327312829d06a98508be2e2795446 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 24 Apr 2018 21:26:06 +0300 Subject: [PATCH 33/47] use randomized exponential backoff in error retry for persistent client registrations --- client.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 6e4e0d4..e65b690 100644 --- a/client.go +++ b/client.go @@ -3,6 +3,7 @@ package rendezvous import ( "context" "fmt" + "math/rand" "time" pb "github.com/libp2p/go-libp2p-rendezvous/pb" @@ -92,9 +93,21 @@ func Register(ctx context.Context, rz Rendezvous, ns string, ttl int) error { } func registerRefresh(ctx context.Context, rz Rendezvous, ns string, ttl int) { - refresh := time.Duration(ttl-30) * time.Second + var refresh time.Duration + errcount := 0 for { + if errcount > 0 { + // do randomized exponential backoff, up to ~4 hours + if errcount > 7 { + errcount = 7 + } + backoff := 2 << uint(errcount) + refresh = 5*time.Minute + time.Duration(rand.Intn(backoff*60000))*time.Millisecond + } else { + refresh = time.Duration(ttl-30) * time.Second + } + select { case <-time.After(refresh): case <-ctx.Done(): @@ -104,6 +117,9 @@ func registerRefresh(ctx context.Context, rz Rendezvous, ns string, ttl int) { err := rz.Register(ctx, ns, ttl) if err != nil { log.Errorf("Error registering [%s]: %s", ns, err.Error()) + errcount++ + } else { + errcount = 0 } } } From aa7f9daaa8818ae17ea2e157361e228f7703d3d0 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 25 Apr 2018 11:06:08 +0300 Subject: [PATCH 34/47] client: add TODO for robust discovery error recovery --- client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client.go b/client.go index e65b690..bf2daa3 100644 --- a/client.go +++ b/client.go @@ -215,6 +215,9 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist for { regs, cookie, err = discoverQuery(ns, batch, cookie, r, w) if err != nil { + // TODO robust error recovery + // - handle closed streams with backoff + new stream, preserving the cookie + // - handle E_INVALID_COOKIE errors in that case to restart the discovery log.Errorf("Error in discovery [%s]: %s", ns, err.Error()) return } From c487c2077b1528816577f043c1f56d143915a63b Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 26 Apr 2018 14:06:58 +0300 Subject: [PATCH 35/47] refactor database interface and implementation into db subpackage We now have: - db/dbi.go -- interface, no dependency on any particular database - db/sqlite/... -- sqlite implementation, depends on dbi - the rendezvous.NewRendezvousService API has been redefined to NewRendezvouServiceWithDB service importer constructs the database of choice - the rendezvous package has no dependences on db implementation, so clients can import without linking SQLite in the binary --- client_test.go | 4 ++-- db/dbi.go | 21 +++++++++++++++++++++ db.go => db/sqlite/db.go | 13 +++++++++---- db_test.go => db/sqlite/db_test.go | 2 +- proto.go | 10 ++-------- svc.go | 16 +++------------- svc_test.go | 14 ++++++++++++-- 7 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 db/dbi.go rename db.go => db/sqlite/db.go (96%) rename db_test.go => db/sqlite/db_test.go (99%) diff --git a/client_test.go b/client_test.go index 6182cf3..68d1b29 100644 --- a/client_test.go +++ b/client_test.go @@ -15,7 +15,7 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { hosts := getRendezvousHosts(t, ctx, 5) - svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") if err != nil { t.Fatal(err) } @@ -74,7 +74,7 @@ func TestClientRegistrationAndDiscoveryAsync(t *testing.T) { hosts := getRendezvousHosts(t, ctx, 5) - svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") if err != nil { t.Fatal(err) } diff --git a/db/dbi.go b/db/dbi.go new file mode 100644 index 0000000..b6fe8f6 --- /dev/null +++ b/db/dbi.go @@ -0,0 +1,21 @@ +package dbi + +import ( + peer "github.com/libp2p/go-libp2p-peer" +) + +type RegistrationRecord struct { + Id peer.ID + Addrs [][]byte + Ns string + Ttl int +} + +type DB interface { + Close() error + Register(p peer.ID, ns string, addrs [][]byte, ttl int) error + Unregister(p peer.ID, ns string) error + CountRegistrations(p peer.ID) (int, error) + Discover(ns string, cookie []byte, limit int) ([]RegistrationRecord, []byte, error) + ValidCookie(ns string, cookie []byte) bool +} diff --git a/db.go b/db/sqlite/db.go similarity index 96% rename from db.go rename to db/sqlite/db.go index 0265d1f..356ed68 100644 --- a/db.go +++ b/db/sqlite/db.go @@ -1,4 +1,4 @@ -package rendezvous +package db import ( "bytes" @@ -11,11 +11,16 @@ import ( "os" "time" + dbi "github.com/libp2p/go-libp2p-rendezvous/db" + _ "github.com/mattn/go-sqlite3" + logging "github.com/ipfs/go-log" peer "github.com/libp2p/go-libp2p-peer" ) +var log = logging.Logger("rendezvous/db") + type DB struct { db *sql.DB @@ -240,7 +245,7 @@ func (db *DB) Unregister(p peer.ID, ns string) error { return err } -func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecord, []byte, error) { +func (db *DB) Discover(ns string, cookie []byte, limit int) ([]dbi.RegistrationRecord, []byte, error) { now := time.Now().Unix() var ( @@ -278,10 +283,10 @@ func (db *DB) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecor defer rows.Close() - regs := make([]RegistrationRecord, 0, limit) + regs := make([]dbi.RegistrationRecord, 0, limit) for rows.Next() { var ( - reg RegistrationRecord + reg dbi.RegistrationRecord rid string rns string expire int64 diff --git a/db_test.go b/db/sqlite/db_test.go similarity index 99% rename from db_test.go rename to db/sqlite/db_test.go index c5b192e..20087c0 100644 --- a/db_test.go +++ b/db/sqlite/db_test.go @@ -1,4 +1,4 @@ -package rendezvous +package db import ( "bytes" diff --git a/proto.go b/proto.go index c1f004e..b145f00 100644 --- a/proto.go +++ b/proto.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + db "github.com/libp2p/go-libp2p-rendezvous/db" pb "github.com/libp2p/go-libp2p-rendezvous/pb" logging "github.com/ipfs/go-log" @@ -21,13 +22,6 @@ const ( DefaultTTL = 2 * 3600 // 2hr ) -type RegistrationRecord struct { - Id peer.ID - Addrs [][]byte - Ns string - Ttl int -} - type RendezvousError struct { Status pb.Message_ResponseStatus Text string @@ -120,7 +114,7 @@ func newRegisterResponseError(status pb.Message_ResponseStatus, text string) *pb return r } -func newDiscoverResponse(regs []RegistrationRecord, cookie []byte) *pb.Message_DiscoverResponse { +func newDiscoverResponse(regs []db.RegistrationRecord, cookie []byte) *pb.Message_DiscoverResponse { r := new(pb.Message_DiscoverResponse) r.Status = pb.Message_OK.Enum() diff --git a/svc.go b/svc.go index 14e2de6..b2bb100 100644 --- a/svc.go +++ b/svc.go @@ -1,9 +1,9 @@ package rendezvous import ( - "context" "fmt" + db "github.com/libp2p/go-libp2p-rendezvous/db" pb "github.com/libp2p/go-libp2p-rendezvous/pb" ggio "github.com/gogo/protobuf/io" @@ -21,7 +21,7 @@ const ( ) type RendezvousService struct { - DB *DB + DB db.DB rzs []RendezvousSync } @@ -30,17 +30,7 @@ type RendezvousSync interface { Unregister(p peer.ID, ns string) } -func NewRendezvousService(ctx context.Context, host host.Host, dbpath string, rzs ...RendezvousSync) (*RendezvousService, error) { - db, err := OpenDB(ctx, dbpath) - if err != nil { - return nil, err - } - - rz := NewRendezvousServiceWithDB(host, db, rzs...) - return rz, nil -} - -func NewRendezvousServiceWithDB(host host.Host, db *DB, rzs ...RendezvousSync) *RendezvousService { +func NewRendezvousService(host host.Host, db db.DB, rzs ...RendezvousSync) *RendezvousService { rz := &RendezvousService{DB: db, rzs: rzs} host.SetStreamHandler(RendezvousProto, rz.handleStream) return rz diff --git a/svc_test.go b/svc_test.go index c0631dc..71e3f35 100644 --- a/svc_test.go +++ b/svc_test.go @@ -6,6 +6,7 @@ import ( "math/rand" "testing" + db "github.com/libp2p/go-libp2p-rendezvous/db/sqlite" pb "github.com/libp2p/go-libp2p-rendezvous/pb" ggio "github.com/gogo/protobuf/io" @@ -53,13 +54,22 @@ func getRendezvousClients(t *testing.T, hosts []host.Host) []Rendezvous { return clients } +func makeRendezvousService(ctx context.Context, host host.Host, path string) (*RendezvousService, error) { + dbi, err := db.OpenDB(ctx, path) + if err != nil { + return nil, err + } + + return NewRendezvousService(host, dbi), nil +} + func TestSVCRegistrationAndDiscovery(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() hosts := getRendezvousHosts(t, ctx, 5) - svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") if err != nil { t.Fatal(err) } @@ -169,7 +179,7 @@ func TestSVCErrors(t *testing.T) { hosts := getRendezvousHosts(t, ctx, 2) - svc, err := NewRendezvousService(ctx, hosts[0], ":memory:") + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") if err != nil { t.Fatal(err) } From baf1e4e61812c08f5e25ac019e04cbabdced4ce4 Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 26 Apr 2018 14:30:47 +0300 Subject: [PATCH 36/47] don't leak database error details in internal errors --- svc.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/svc.go b/svc.go index b2bb100..57227f5 100644 --- a/svc.go +++ b/svc.go @@ -151,7 +151,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * rcount, err := rz.DB.CountRegistrations(p) if err != nil { log.Errorf("Error counting registrations: %s", err.Error()) - return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, "database error") } if rcount > MaxRegistrations { @@ -163,7 +163,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * err = rz.DB.Register(p, ns, maddrs, ttl) if err != nil { log.Errorf("Error registering: %s", err.Error()) - return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, "database error") } log.Infof("registered peer %s %s (%d)", p, ns, ttl) @@ -225,7 +225,7 @@ func (rz *RendezvousService) handleDiscover(p peer.ID, m *pb.Message_Discover) * regs, cookie, err := rz.DB.Discover(ns, cookie, limit) if err != nil { log.Errorf("Error in query: %s", err.Error()) - return newDiscoverResponseError(pb.Message_E_INTERNAL_ERROR, err.Error()) + return newDiscoverResponseError(pb.Message_E_INTERNAL_ERROR, "database error") } log.Infof("discover query: %s %s -> %d", p, ns, len(regs)) From c540724f1f9f5cb838b6d050b7fb0c5bcbdd4547 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 28 Apr 2018 12:05:21 +0300 Subject: [PATCH 37/47] two interfaces for client-side: RendezvousPoint and RendezvousClient RendezvousClient soon to be stateful. --- client.go | 71 +++++++++++++++++++++++++++++++++----------------- client_test.go | 22 +++++++++++----- svc_test.go | 8 +++--- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/client.go b/client.go index bf2daa3..4ed8b87 100644 --- a/client.go +++ b/client.go @@ -19,7 +19,7 @@ var ( DiscoverAsyncInterval = 2 * time.Minute ) -type Rendezvous interface { +type RendezvousPoint 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, cookie []byte) ([]Registration, []byte, error) @@ -32,20 +32,39 @@ type Registration struct { Ttl int } -func NewRendezvousClient(host host.Host, rp peer.ID) Rendezvous { - return &client{ +type RendezvousClient 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, cookie []byte) ([]pstore.PeerInfo, []byte, error) + DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) +} + +func NewRendezvousPoint(host host.Host, p peer.ID) RendezvousPoint { + return &rendezvousPoint{ host: host, - rp: rp, + p: p, } } -type client struct { +type rendezvousPoint struct { host host.Host - rp peer.ID + p peer.ID } -func (cli *client) Register(ctx context.Context, ns string, ttl int) error { - s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) +func NewRendezvousClient(host host.Host, rp peer.ID) RendezvousClient { + return NewRendezvousClientWithPoint(NewRendezvousPoint(host, rp)) +} + +func NewRendezvousClientWithPoint(rp RendezvousPoint) RendezvousClient { + return &rendezvousClient{rp: rp} +} + +type rendezvousClient struct { + rp RendezvousPoint +} + +func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) error { + s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { return err } @@ -54,7 +73,7 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) - req := newRegisterMessage(ns, pstore.PeerInfo{ID: cli.host.ID(), Addrs: cli.host.Addrs()}, ttl) + req := newRegisterMessage(ns, pstore.PeerInfo{ID: rp.host.ID(), Addrs: rp.host.Addrs()}, ttl) err = w.WriteMsg(req) if err != nil { return err @@ -78,21 +97,21 @@ func (cli *client) Register(ctx context.Context, ns string, ttl int) error { return nil } -func Register(ctx context.Context, rz Rendezvous, ns string, ttl int) error { +func (rc *rendezvousClient) Register(ctx context.Context, ns string, ttl int) error { if ttl < 120 { return fmt.Errorf("registration TTL is too short") } - err := rz.Register(ctx, ns, ttl) + err := rc.rp.Register(ctx, ns, ttl) if err != nil { return err } - go registerRefresh(ctx, rz, ns, ttl) + go registerRefresh(ctx, rc.rp, ns, ttl) return nil } -func registerRefresh(ctx context.Context, rz Rendezvous, ns string, ttl int) { +func registerRefresh(ctx context.Context, rz RendezvousPoint, ns string, ttl int) { var refresh time.Duration errcount := 0 @@ -124,20 +143,24 @@ func registerRefresh(ctx context.Context, rz Rendezvous, ns string, ttl int) { } } -func (cli *client) Unregister(ctx context.Context, ns string) error { - s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) +func (rp *rendezvousPoint) Unregister(ctx context.Context, ns string) error { + s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { return err } defer s.Close() w := ggio.NewDelimitedWriter(s) - req := newUnregisterMessage(ns, cli.host.ID()) + req := newUnregisterMessage(ns, rp.host.ID()) return w.WriteMsg(req) } -func (cli *client) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]Registration, []byte, error) { - s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) +func (rc *rendezvousClient) Unregister(ctx context.Context, ns string) error { + return rc.rp.Unregister(ctx, ns) +} + +func (rp *rendezvousPoint) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]Registration, []byte, error) { + s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { return nil, nil, err } @@ -186,8 +209,8 @@ func discoverQuery(ns string, limit int, cookie []byte, r ggio.Reader, w ggio.Wr return result, res.GetDiscoverResponse().GetCookie(), nil } -func (cli *client) DiscoverAsync(ctx context.Context, ns string) (<-chan Registration, error) { - s, err := cli.host.NewStream(ctx, cli.rp, RendezvousProto) +func (rp *rendezvousPoint) DiscoverAsync(ctx context.Context, ns string) (<-chan Registration, error) { + s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { return nil, err } @@ -241,8 +264,8 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist } } -func DiscoverPeers(ctx context.Context, rz Rendezvous, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { - regs, cookie, err := rz.Discover(ctx, ns, limit, cookie) +func (rc *rendezvousClient) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { + regs, cookie, err := rc.rp.Discover(ctx, ns, limit, cookie) if err != nil { return nil, nil, err } @@ -255,8 +278,8 @@ func DiscoverPeers(ctx context.Context, rz Rendezvous, ns string, limit int, coo return pinfos, cookie, nil } -func DiscoverPeersAsync(ctx context.Context, rz Rendezvous, ns string) (<-chan pstore.PeerInfo, error) { - rch, err := rz.DiscoverAsync(ctx, ns) +func (rc *rendezvousClient) DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { + rch, err := rc.rp.DiscoverAsync(ctx, ns) if err != nil { return nil, err } diff --git a/client_test.go b/client_test.go index 68d1b29..0c33200 100644 --- a/client_test.go +++ b/client_test.go @@ -9,6 +9,14 @@ import ( pstore "github.com/libp2p/go-libp2p-peerstore" ) +func getRendezvousClients(t *testing.T, hosts []host.Host) []RendezvousClient { + clients := make([]RendezvousClient, len(hosts)-1) + for i, host := range hosts[1:] { + clients[i] = NewRendezvousClient(host, hosts[0].ID()) + } + return clients +} + func TestClientRegistrationAndDiscovery(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -23,12 +31,12 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { clients := getRendezvousClients(t, hosts) - err = Register(ctx, clients[0], "foo1", DefaultTTL) + err = clients[0].Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } - pi, cookie, err := DiscoverPeers(ctx, clients[0], "foo1", 0, nil) + pi, cookie, err := clients[0].Discover(ctx, "foo1", 0, nil) if err != nil { t.Fatal(err) } @@ -38,12 +46,12 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { checkPeerInfo(t, pi[0], hosts[1]) for i, client := range clients[1:] { - err = Register(ctx, client, "foo1", DefaultTTL) + err = client.Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } - pi, cookie, err = DiscoverPeers(ctx, clients[0], "foo1", 10, cookie) + pi, cookie, err = clients[0].Discover(ctx, "foo1", 10, cookie) if err != nil { t.Fatal(err) } @@ -54,7 +62,7 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { } for _, client := range clients[1:] { - pi, _, err = DiscoverPeers(ctx, client, "foo1", 10, nil) + pi, _, err = client.Discover(ctx, "foo1", 10, nil) if err != nil { t.Fatal(err) } @@ -84,13 +92,13 @@ func TestClientRegistrationAndDiscoveryAsync(t *testing.T) { DiscoverAsyncInterval = 1 * time.Second - ch, err := DiscoverPeersAsync(ctx, clients[0], "foo1") + ch, err := clients[0].DiscoverAsync(ctx, "foo1") if err != nil { t.Fatal(err) } for i, client := range clients[0:] { - err = Register(ctx, client, "foo1", DefaultTTL) + err = client.Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } diff --git a/svc_test.go b/svc_test.go index 71e3f35..7a7ed5c 100644 --- a/svc_test.go +++ b/svc_test.go @@ -46,10 +46,10 @@ func connect(t *testing.T, a, b host.Host) { } } -func getRendezvousClients(t *testing.T, hosts []host.Host) []Rendezvous { - clients := make([]Rendezvous, len(hosts)-1) +func getRendezvousPoints(t *testing.T, hosts []host.Host) []RendezvousPoint { + clients := make([]RendezvousPoint, len(hosts)-1) for i, host := range hosts[1:] { - clients[i] = NewRendezvousClient(host, hosts[0].ID()) + clients[i] = NewRendezvousPoint(host, hosts[0].ID()) } return clients } @@ -75,7 +75,7 @@ func TestSVCRegistrationAndDiscovery(t *testing.T) { } defer svc.DB.Close() - clients := getRendezvousClients(t, hosts) + clients := getRendezvousPoints(t, hosts) err = clients[0].Register(ctx, "foo1", 60) if err != nil { From 1ee2b55a9f4a96818e15b9c6186a762b4b969e41 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 18 Jan 2019 15:22:49 +0200 Subject: [PATCH 38/47] update protobuf --- pb/rendezvous.pb.go | 1975 ++++++++++++++++++++++++++++++++++++++++++- pb/rendezvous.proto | 2 + 2 files changed, 1936 insertions(+), 41 deletions(-) diff --git a/pb/rendezvous.pb.go b/pb/rendezvous.pb.go index a8b8751..50c535a 100644 --- a/pb/rendezvous.pb.go +++ b/pb/rendezvous.pb.go @@ -1,27 +1,25 @@ -// Code generated by protoc-gen-gogo. +// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: rendezvous.proto -// DO NOT EDIT! -/* -Package rendezvous_pb is a generated protocol buffer package. - -It is generated from these files: - rendezvous.proto - -It has these top-level messages: - Message -*/ package rendezvous_pb import proto "github.com/gogo/protobuf/proto" import fmt "fmt" import math "math" +import io "io" + // 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 + type Message_MessageType int32 const ( @@ -63,6 +61,9 @@ func (x *Message_MessageType) UnmarshalJSON(data []byte) error { *x = Message_MessageType(value) return nil } +func (Message_MessageType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 0} +} type Message_ResponseStatus int32 @@ -74,6 +75,7 @@ const ( Message_E_INVALID_COOKIE Message_ResponseStatus = 103 Message_E_NOT_AUTHORIZED Message_ResponseStatus = 200 Message_E_INTERNAL_ERROR Message_ResponseStatus = 300 + Message_E_UNAVAILABLE Message_ResponseStatus = 400 ) var Message_ResponseStatus_name = map[int32]string{ @@ -84,15 +86,17 @@ var Message_ResponseStatus_name = map[int32]string{ 103: "E_INVALID_COOKIE", 200: "E_NOT_AUTHORIZED", 300: "E_INTERNAL_ERROR", + 400: "E_UNAVAILABLE", } var Message_ResponseStatus_value = map[string]int32{ - "OK": 0, + "OK": 0, "E_INVALID_NAMESPACE": 100, "E_INVALID_PEER_INFO": 101, "E_INVALID_TTL": 102, "E_INVALID_COOKIE": 103, "E_NOT_AUTHORIZED": 200, "E_INTERNAL_ERROR": 300, + "E_UNAVAILABLE": 400, } func (x Message_ResponseStatus) Enum() *Message_ResponseStatus { @@ -111,20 +115,54 @@ func (x *Message_ResponseStatus) UnmarshalJSON(data []byte) error { *x = Message_ResponseStatus(value) return nil } +func (Message_ResponseStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 1} +} type Message struct { - Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=rendezvous.pb.Message_MessageType" json:"type,omitempty"` - Register *Message_Register `protobuf:"bytes,2,opt,name=register" json:"register,omitempty"` - RegisterResponse *Message_RegisterResponse `protobuf:"bytes,3,opt,name=registerResponse" json:"registerResponse,omitempty"` - Unregister *Message_Unregister `protobuf:"bytes,4,opt,name=unregister" json:"unregister,omitempty"` - Discover *Message_Discover `protobuf:"bytes,5,opt,name=discover" json:"discover,omitempty"` - DiscoverResponse *Message_DiscoverResponse `protobuf:"bytes,6,opt,name=discoverResponse" json:"discoverResponse,omitempty"` - XXX_unrecognized []byte `json:"-"` + Type *Message_MessageType `protobuf:"varint,1,opt,name=type,enum=rendezvous.pb.Message_MessageType" json:"type,omitempty"` + Register *Message_Register `protobuf:"bytes,2,opt,name=register" json:"register,omitempty"` + RegisterResponse *Message_RegisterResponse `protobuf:"bytes,3,opt,name=registerResponse" json:"registerResponse,omitempty"` + Unregister *Message_Unregister `protobuf:"bytes,4,opt,name=unregister" json:"unregister,omitempty"` + Discover *Message_Discover `protobuf:"bytes,5,opt,name=discover" json:"discover,omitempty"` + DiscoverResponse *Message_DiscoverResponse `protobuf:"bytes,6,opt,name=discoverResponse" json:"discoverResponse,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message) Reset() { *m = Message{} } func (m *Message) String() string { return proto.CompactTextString(m) } func (*Message) ProtoMessage() {} +func (*Message) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0} +} +func (m *Message) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message.Merge(dst, src) +} +func (m *Message) XXX_Size() int { + return m.Size() +} +func (m *Message) XXX_DiscardUnknown() { + xxx_messageInfo_Message.DiscardUnknown(m) +} + +var xxx_messageInfo_Message proto.InternalMessageInfo func (m *Message) GetType() Message_MessageType { if m != nil && m.Type != nil { @@ -169,14 +207,45 @@ func (m *Message) GetDiscoverResponse() *Message_DiscoverResponse { } type Message_PeerInfo struct { - Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` - Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` - XXX_unrecognized []byte `json:"-"` + Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs" json:"addrs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_PeerInfo) Reset() { *m = Message_PeerInfo{} } func (m *Message_PeerInfo) String() string { return proto.CompactTextString(m) } func (*Message_PeerInfo) ProtoMessage() {} +func (*Message_PeerInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 0} +} +func (m *Message_PeerInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_PeerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_PeerInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_PeerInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_PeerInfo.Merge(dst, src) +} +func (m *Message_PeerInfo) XXX_Size() int { + return m.Size() +} +func (m *Message_PeerInfo) XXX_DiscardUnknown() { + xxx_messageInfo_Message_PeerInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_PeerInfo proto.InternalMessageInfo func (m *Message_PeerInfo) GetId() []byte { if m != nil { @@ -193,15 +262,46 @@ func (m *Message_PeerInfo) GetAddrs() [][]byte { } type Message_Register struct { - Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` - Peer *Message_PeerInfo `protobuf:"bytes,2,opt,name=peer" json:"peer,omitempty"` - Ttl *int64 `protobuf:"varint,3,opt,name=ttl" json:"ttl,omitempty"` - XXX_unrecognized []byte `json:"-"` + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Peer *Message_PeerInfo `protobuf:"bytes,2,opt,name=peer" json:"peer,omitempty"` + Ttl *int64 `protobuf:"varint,3,opt,name=ttl" json:"ttl,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_Register) Reset() { *m = Message_Register{} } func (m *Message_Register) String() string { return proto.CompactTextString(m) } func (*Message_Register) ProtoMessage() {} +func (*Message_Register) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 1} +} +func (m *Message_Register) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_Register) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_Register.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_Register) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_Register.Merge(dst, src) +} +func (m *Message_Register) XXX_Size() int { + return m.Size() +} +func (m *Message_Register) XXX_DiscardUnknown() { + xxx_messageInfo_Message_Register.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_Register proto.InternalMessageInfo func (m *Message_Register) GetNs() string { if m != nil && m.Ns != nil { @@ -225,14 +325,46 @@ func (m *Message_Register) GetTtl() int64 { } type Message_RegisterResponse struct { - Status *Message_ResponseStatus `protobuf:"varint,1,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` - StatusText *string `protobuf:"bytes,2,opt,name=statusText" json:"statusText,omitempty"` - XXX_unrecognized []byte `json:"-"` + Status *Message_ResponseStatus `protobuf:"varint,1,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` + StatusText *string `protobuf:"bytes,2,opt,name=statusText" json:"statusText,omitempty"` + Ttl *int64 `protobuf:"varint,3,opt,name=ttl" json:"ttl,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_RegisterResponse) Reset() { *m = Message_RegisterResponse{} } func (m *Message_RegisterResponse) String() string { return proto.CompactTextString(m) } func (*Message_RegisterResponse) ProtoMessage() {} +func (*Message_RegisterResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 2} +} +func (m *Message_RegisterResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_RegisterResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_RegisterResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_RegisterResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_RegisterResponse.Merge(dst, src) +} +func (m *Message_RegisterResponse) XXX_Size() int { + return m.Size() +} +func (m *Message_RegisterResponse) XXX_DiscardUnknown() { + xxx_messageInfo_Message_RegisterResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_RegisterResponse proto.InternalMessageInfo func (m *Message_RegisterResponse) GetStatus() Message_ResponseStatus { if m != nil && m.Status != nil { @@ -248,15 +380,53 @@ func (m *Message_RegisterResponse) GetStatusText() string { return "" } +func (m *Message_RegisterResponse) GetTtl() int64 { + if m != nil && m.Ttl != nil { + return *m.Ttl + } + return 0 +} + type Message_Unregister struct { - Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` - Id []byte `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` - XXX_unrecognized []byte `json:"-"` + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Id []byte `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_Unregister) Reset() { *m = Message_Unregister{} } func (m *Message_Unregister) String() string { return proto.CompactTextString(m) } func (*Message_Unregister) ProtoMessage() {} +func (*Message_Unregister) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 3} +} +func (m *Message_Unregister) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_Unregister) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_Unregister.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_Unregister) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_Unregister.Merge(dst, src) +} +func (m *Message_Unregister) XXX_Size() int { + return m.Size() +} +func (m *Message_Unregister) XXX_DiscardUnknown() { + xxx_messageInfo_Message_Unregister.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_Unregister proto.InternalMessageInfo func (m *Message_Unregister) GetNs() string { if m != nil && m.Ns != nil { @@ -273,15 +443,46 @@ func (m *Message_Unregister) GetId() []byte { } type Message_Discover struct { - Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` - Limit *int64 `protobuf:"varint,2,opt,name=limit" json:"limit,omitempty"` - Cookie []byte `protobuf:"bytes,3,opt,name=cookie" json:"cookie,omitempty"` - XXX_unrecognized []byte `json:"-"` + Ns *string `protobuf:"bytes,1,opt,name=ns" json:"ns,omitempty"` + Limit *int64 `protobuf:"varint,2,opt,name=limit" json:"limit,omitempty"` + Cookie []byte `protobuf:"bytes,3,opt,name=cookie" json:"cookie,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_Discover) Reset() { *m = Message_Discover{} } func (m *Message_Discover) String() string { return proto.CompactTextString(m) } func (*Message_Discover) ProtoMessage() {} +func (*Message_Discover) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 4} +} +func (m *Message_Discover) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_Discover) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_Discover.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_Discover) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_Discover.Merge(dst, src) +} +func (m *Message_Discover) XXX_Size() int { + return m.Size() +} +func (m *Message_Discover) XXX_DiscardUnknown() { + xxx_messageInfo_Message_Discover.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_Discover proto.InternalMessageInfo func (m *Message_Discover) GetNs() string { if m != nil && m.Ns != nil { @@ -305,16 +506,47 @@ func (m *Message_Discover) GetCookie() []byte { } type Message_DiscoverResponse struct { - Registrations []*Message_Register `protobuf:"bytes,1,rep,name=registrations" json:"registrations,omitempty"` - Cookie []byte `protobuf:"bytes,2,opt,name=cookie" json:"cookie,omitempty"` - Status *Message_ResponseStatus `protobuf:"varint,3,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` - StatusText *string `protobuf:"bytes,4,opt,name=statusText" json:"statusText,omitempty"` - XXX_unrecognized []byte `json:"-"` + Registrations []*Message_Register `protobuf:"bytes,1,rep,name=registrations" json:"registrations,omitempty"` + Cookie []byte `protobuf:"bytes,2,opt,name=cookie" json:"cookie,omitempty"` + Status *Message_ResponseStatus `protobuf:"varint,3,opt,name=status,enum=rendezvous.pb.Message_ResponseStatus" json:"status,omitempty"` + StatusText *string `protobuf:"bytes,4,opt,name=statusText" json:"statusText,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Message_DiscoverResponse) Reset() { *m = Message_DiscoverResponse{} } func (m *Message_DiscoverResponse) String() string { return proto.CompactTextString(m) } func (*Message_DiscoverResponse) ProtoMessage() {} +func (*Message_DiscoverResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_rendezvous_af6820b250ca4668, []int{0, 5} +} +func (m *Message_DiscoverResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Message_DiscoverResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Message_DiscoverResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *Message_DiscoverResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_Message_DiscoverResponse.Merge(dst, src) +} +func (m *Message_DiscoverResponse) XXX_Size() int { + return m.Size() +} +func (m *Message_DiscoverResponse) XXX_DiscardUnknown() { + xxx_messageInfo_Message_DiscoverResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_Message_DiscoverResponse proto.InternalMessageInfo func (m *Message_DiscoverResponse) GetRegistrations() []*Message_Register { if m != nil { @@ -355,3 +587,1664 @@ func init() { proto.RegisterEnum("rendezvous.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value) proto.RegisterEnum("rendezvous.pb.Message_ResponseStatus", Message_ResponseStatus_name, Message_ResponseStatus_value) } +func (m *Message) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Type != nil { + dAtA[i] = 0x8 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Type)) + } + if m.Register != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.Register.Size())) + n1, err := m.Register.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if m.RegisterResponse != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.RegisterResponse.Size())) + n2, err := m.RegisterResponse.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + } + if m.Unregister != nil { + dAtA[i] = 0x22 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.Unregister.Size())) + n3, err := m.Unregister.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + } + if m.Discover != nil { + dAtA[i] = 0x2a + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.Discover.Size())) + n4, err := m.Discover.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + } + if m.DiscoverResponse != nil { + dAtA[i] = 0x32 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.DiscoverResponse.Size())) + n5, err := m.DiscoverResponse.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_PeerInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_PeerInfo) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Id != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(m.Id))) + i += copy(dAtA[i:], m.Id) + } + if len(m.Addrs) > 0 { + for _, b := range m.Addrs { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(b))) + i += copy(dAtA[i:], b) + } + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_Register) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_Register) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Ns != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(*m.Ns))) + i += copy(dAtA[i:], *m.Ns) + } + if m.Peer != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(m.Peer.Size())) + n6, err := m.Peer.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 + } + if m.Ttl != nil { + dAtA[i] = 0x18 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Ttl)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_RegisterResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_RegisterResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Status != nil { + dAtA[i] = 0x8 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Status)) + } + if m.StatusText != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(*m.StatusText))) + i += copy(dAtA[i:], *m.StatusText) + } + if m.Ttl != nil { + dAtA[i] = 0x18 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Ttl)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_Unregister) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_Unregister) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Ns != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(*m.Ns))) + i += copy(dAtA[i:], *m.Ns) + } + if m.Id != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(m.Id))) + i += copy(dAtA[i:], m.Id) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_Discover) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_Discover) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Ns != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(*m.Ns))) + i += copy(dAtA[i:], *m.Ns) + } + if m.Limit != nil { + dAtA[i] = 0x10 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Limit)) + } + if m.Cookie != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(m.Cookie))) + i += copy(dAtA[i:], m.Cookie) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *Message_DiscoverResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Message_DiscoverResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Registrations) > 0 { + for _, msg := range m.Registrations { + dAtA[i] = 0xa + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + if m.Cookie != nil { + dAtA[i] = 0x12 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(m.Cookie))) + i += copy(dAtA[i:], m.Cookie) + } + if m.Status != nil { + dAtA[i] = 0x18 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(*m.Status)) + } + if m.StatusText != nil { + dAtA[i] = 0x22 + i++ + i = encodeVarintRendezvous(dAtA, i, uint64(len(*m.StatusText))) + i += copy(dAtA[i:], *m.StatusText) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func encodeVarintRendezvous(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *Message) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != nil { + n += 1 + sovRendezvous(uint64(*m.Type)) + } + if m.Register != nil { + l = m.Register.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.RegisterResponse != nil { + l = m.RegisterResponse.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Unregister != nil { + l = m.Unregister.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Discover != nil { + l = m.Discover.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.DiscoverResponse != nil { + l = m.DiscoverResponse.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_PeerInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != nil { + l = len(m.Id) + n += 1 + l + sovRendezvous(uint64(l)) + } + if len(m.Addrs) > 0 { + for _, b := range m.Addrs { + l = len(b) + n += 1 + l + sovRendezvous(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_Register) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ns != nil { + l = len(*m.Ns) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Peer != nil { + l = m.Peer.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Ttl != nil { + n += 1 + sovRendezvous(uint64(*m.Ttl)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_RegisterResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Status != nil { + n += 1 + sovRendezvous(uint64(*m.Status)) + } + if m.StatusText != nil { + l = len(*m.StatusText) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Ttl != nil { + n += 1 + sovRendezvous(uint64(*m.Ttl)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_Unregister) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ns != nil { + l = len(*m.Ns) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Id != nil { + l = len(m.Id) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_Discover) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Ns != nil { + l = len(*m.Ns) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Limit != nil { + n += 1 + sovRendezvous(uint64(*m.Limit)) + } + if m.Cookie != nil { + l = len(m.Cookie) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Message_DiscoverResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Registrations) > 0 { + for _, e := range m.Registrations { + l = e.Size() + n += 1 + l + sovRendezvous(uint64(l)) + } + } + if m.Cookie != nil { + l = len(m.Cookie) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.Status != nil { + n += 1 + sovRendezvous(uint64(*m.Status)) + } + if m.StatusText != nil { + l = len(*m.StatusText) + n += 1 + l + sovRendezvous(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovRendezvous(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozRendezvous(x uint64) (n int) { + return sovRendezvous(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Message) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Message: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Message: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var v Message_MessageType + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (Message_MessageType(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Type = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Register", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Register == nil { + m.Register = &Message_Register{} + } + if err := m.Register.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RegisterResponse", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RegisterResponse == nil { + m.RegisterResponse = &Message_RegisterResponse{} + } + if err := m.RegisterResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Unregister", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Unregister == nil { + m.Unregister = &Message_Unregister{} + } + if err := m.Unregister.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Discover", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Discover == nil { + m.Discover = &Message_Discover{} + } + if err := m.Discover.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DiscoverResponse", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.DiscoverResponse == nil { + m.DiscoverResponse = &Message_DiscoverResponse{} + } + if err := m.DiscoverResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_PeerInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PeerInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PeerInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = append(m.Id[:0], dAtA[iNdEx:postIndex]...) + if m.Id == nil { + m.Id = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addrs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addrs = append(m.Addrs, make([]byte, postIndex-iNdEx)) + copy(m.Addrs[len(m.Addrs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_Register) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Register: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Register: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ns", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Ns = &s + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Peer", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Peer == nil { + m.Peer = &Message_PeerInfo{} + } + if err := m.Peer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ttl", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Ttl = &v + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_RegisterResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RegisterResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisterResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var v Message_ResponseStatus + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (Message_ResponseStatus(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Status = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StatusText", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.StatusText = &s + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ttl", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Ttl = &v + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_Unregister) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Unregister: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Unregister: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ns", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Ns = &s + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = append(m.Id[:0], dAtA[iNdEx:postIndex]...) + if m.Id == nil { + m.Id = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_Discover) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Discover: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Discover: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ns", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Ns = &s + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Limit = &v + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cookie", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cookie = append(m.Cookie[:0], dAtA[iNdEx:postIndex]...) + if m.Cookie == nil { + m.Cookie = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Message_DiscoverResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiscoverResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiscoverResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Registrations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Registrations = append(m.Registrations, &Message_Register{}) + if err := m.Registrations[len(m.Registrations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Cookie", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Cookie = append(m.Cookie[:0], dAtA[iNdEx:postIndex]...) + if m.Cookie == nil { + m.Cookie = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var v Message_ResponseStatus + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (Message_ResponseStatus(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Status = &v + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StatusText", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRendezvous + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRendezvous + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.StatusText = &s + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRendezvous(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRendezvous + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRendezvous(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRendezvous + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRendezvous + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRendezvous + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthRendezvous + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRendezvous + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipRendezvous(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthRendezvous = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRendezvous = fmt.Errorf("proto: integer overflow") +) + +func init() { proto.RegisterFile("rendezvous.proto", fileDescriptor_rendezvous_af6820b250ca4668) } + +var fileDescriptor_rendezvous_af6820b250ca4668 = []byte{ + // 556 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xc1, 0x72, 0xd2, 0x40, + 0x18, 0xc7, 0x9b, 0x04, 0x30, 0x7c, 0x04, 0x66, 0xbb, 0xda, 0x91, 0xe1, 0x80, 0xc8, 0xd8, 0x91, + 0x8b, 0x8c, 0x76, 0xa6, 0xde, 0x53, 0x58, 0x75, 0xa7, 0x34, 0x61, 0x36, 0x81, 0x83, 0x97, 0x0c, + 0x36, 0x5b, 0x26, 0x5a, 0x09, 0x93, 0x0d, 0x1d, 0xeb, 0x53, 0xf8, 0x12, 0xde, 0xbc, 0xfa, 0x0e, + 0x3d, 0xfa, 0x08, 0x0e, 0x57, 0x5f, 0xc2, 0x49, 0x42, 0x42, 0x60, 0xa4, 0x75, 0x7a, 0x4a, 0xf6, + 0xdb, 0xff, 0xef, 0xfb, 0xfe, 0xfb, 0xcf, 0x06, 0x50, 0xc0, 0x67, 0x2e, 0xff, 0x7a, 0xe5, 0x2f, + 0x44, 0x77, 0x1e, 0xf8, 0xa1, 0x8f, 0xab, 0xf9, 0xca, 0x87, 0xf6, 0x1f, 0x15, 0x1e, 0x9c, 0x71, + 0x21, 0x26, 0x53, 0x8e, 0x5f, 0x42, 0x21, 0xbc, 0x9e, 0xf3, 0xba, 0xd4, 0x92, 0x3a, 0xb5, 0xa3, + 0x76, 0x77, 0x43, 0xd9, 0x5d, 0xa9, 0xd2, 0xa7, 0x7d, 0x3d, 0xe7, 0xf8, 0x15, 0xa8, 0x01, 0x9f, + 0x7a, 0x22, 0xe4, 0x41, 0x5d, 0x6e, 0x49, 0x9d, 0xca, 0xd1, 0x93, 0x1d, 0x14, 0x5b, 0xc9, 0xb0, + 0x1e, 0x79, 0x4a, 0xde, 0x19, 0x17, 0x73, 0x7f, 0x26, 0x78, 0x5d, 0x89, 0xd1, 0xe7, 0x77, 0xa0, + 0xa9, 0x1c, 0x1f, 0x03, 0x2c, 0x66, 0xd9, 0xdc, 0x42, 0x0c, 0x3f, 0xdd, 0x01, 0x8f, 0x32, 0x61, + 0x64, 0xd6, 0xf5, 0xc4, 0xb9, 0x7f, 0xc5, 0x83, 0x7a, 0xf1, 0x56, 0xb3, 0xfd, 0x95, 0x2c, 0x32, + 0x9b, 0x22, 0x99, 0xd9, 0xd2, 0xad, 0x66, 0xfb, 0x5b, 0xf2, 0xc6, 0x21, 0xa8, 0x43, 0xce, 0x03, + 0x3a, 0xbb, 0xf0, 0x31, 0x80, 0xec, 0xb9, 0x71, 0xbc, 0x1a, 0xae, 0x42, 0x71, 0xe2, 0xba, 0x81, + 0xa8, 0xcb, 0x2d, 0xa5, 0xa3, 0x35, 0x18, 0xa8, 0x59, 0x44, 0x00, 0xf2, 0x4c, 0xc4, 0xb2, 0x32, + 0x7e, 0x01, 0x85, 0x39, 0xbf, 0x33, 0xdd, 0x6c, 0x42, 0x05, 0x94, 0x30, 0xbc, 0x8c, 0x03, 0x55, + 0x1a, 0x1f, 0x01, 0xfd, 0x23, 0xbb, 0x92, 0x08, 0x27, 0xe1, 0x42, 0xac, 0xbe, 0xf2, 0xe1, 0xce, + 0xd0, 0x13, 0xc0, 0x8a, 0xc5, 0x18, 0x03, 0x24, 0x98, 0xcd, 0xbf, 0x84, 0xb1, 0x99, 0xf2, 0xe6, + 0xac, 0x67, 0x00, 0xb9, 0xa8, 0xf3, 0x27, 0x48, 0x0e, 0x1d, 0x21, 0x5a, 0xe3, 0x18, 0xd4, 0x2c, + 0xdb, 0xbc, 0xa6, 0x0a, 0xc5, 0x4b, 0xef, 0xb3, 0x97, 0x74, 0x56, 0x70, 0x0d, 0x4a, 0xe7, 0xbe, + 0xff, 0xc9, 0x4b, 0x6e, 0x86, 0xd6, 0xf8, 0x2e, 0x01, 0xda, 0x0e, 0x16, 0xbf, 0x86, 0x6a, 0x32, + 0x2f, 0x98, 0x84, 0x9e, 0x1f, 0xb7, 0x52, 0xfe, 0xe7, 0x02, 0xae, 0x9b, 0xc7, 0x9e, 0x72, 0x89, + 0x28, 0xf7, 0x4f, 0x24, 0xba, 0x84, 0xe5, 0xf6, 0x14, 0x2a, 0xf9, 0xbf, 0x43, 0x03, 0x95, 0x91, + 0xb7, 0xd4, 0xb2, 0x09, 0x43, 0x7b, 0xf8, 0x00, 0xf6, 0xd3, 0x95, 0xc3, 0x88, 0x35, 0x34, 0x0d, + 0x8b, 0x20, 0x09, 0xd7, 0x00, 0x46, 0x46, 0x26, 0x93, 0x23, 0xa8, 0x4f, 0xad, 0x9e, 0x39, 0x26, + 0x0c, 0x29, 0x11, 0x94, 0xae, 0xd6, 0x50, 0xa1, 0xfd, 0x53, 0x82, 0xda, 0x96, 0x9f, 0x12, 0xc8, + 0xe6, 0x29, 0xda, 0xc3, 0x8f, 0xe1, 0x21, 0x71, 0xa8, 0x31, 0xd6, 0x07, 0xb4, 0xef, 0x18, 0xfa, + 0x19, 0xb1, 0x86, 0x7a, 0x8f, 0x20, 0x77, 0x73, 0x63, 0x48, 0x08, 0x73, 0xa8, 0xf1, 0xc6, 0x44, + 0x1c, 0xef, 0x43, 0x75, 0xbd, 0x61, 0xdb, 0x03, 0x74, 0x81, 0x1f, 0x01, 0x5a, 0x97, 0x7a, 0xa6, + 0x79, 0x4a, 0x09, 0x9a, 0xe2, 0x83, 0xa8, 0x6a, 0x98, 0xb6, 0xa3, 0x8f, 0xec, 0x77, 0x26, 0xa3, + 0xef, 0x49, 0x1f, 0xdd, 0x48, 0x49, 0x99, 0x1a, 0x36, 0x61, 0x86, 0x3e, 0x70, 0x08, 0x63, 0x26, + 0x43, 0x3f, 0x64, 0x8c, 0xa3, 0xb6, 0x23, 0x43, 0x1f, 0xeb, 0x74, 0xa0, 0x9f, 0x0c, 0x08, 0xfa, + 0xa6, 0x9c, 0x68, 0x37, 0xcb, 0xa6, 0xf4, 0x6b, 0xd9, 0x94, 0x7e, 0x2f, 0x9b, 0xd2, 0xdf, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x26, 0x60, 0x8f, 0xe5, 0x9d, 0x04, 0x00, 0x00, +} diff --git a/pb/rendezvous.proto b/pb/rendezvous.proto index 1526f54..649a2ae 100644 --- a/pb/rendezvous.proto +++ b/pb/rendezvous.proto @@ -17,6 +17,7 @@ message Message { E_INVALID_COOKIE = 103; E_NOT_AUTHORIZED = 200; E_INTERNAL_ERROR = 300; + E_UNAVAILABLE = 400; } message PeerInfo { @@ -33,6 +34,7 @@ message Message { message RegisterResponse { optional ResponseStatus status = 1; optional string statusText = 2; + optional int64 ttl = 3; } message Unregister { From 8846a4b090ba2ebdd2cc85dd72fab486363a650c Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 18 Jan 2019 15:31:50 +0200 Subject: [PATCH 39/47] include ttl in registration response --- proto.go | 4 +++- svc.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/proto.go b/proto.go index b145f00..9ae60f2 100644 --- a/proto.go +++ b/proto.go @@ -101,9 +101,11 @@ func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) { return pstore.PeerInfo{ID: id, Addrs: addrs}, nil } -func newRegisterResponse() *pb.Message_RegisterResponse { +func newRegisterResponse(ttl int) *pb.Message_RegisterResponse { + ttl64 := int64(ttl) r := new(pb.Message_RegisterResponse) r.Status = pb.Message_OK.Enum() + r.Ttl = &ttl64 return r } diff --git a/svc.go b/svc.go index 57227f5..0be1f07 100644 --- a/svc.go +++ b/svc.go @@ -172,7 +172,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * rzs.Register(p, ns, maddrs, ttl) } - return newRegisterResponse() + return newRegisterResponse(ttl) } func (rz *RendezvousService) handleUnregister(p peer.ID, m *pb.Message_Unregister) error { From 3c726d2ea951bd006ff1a42aa9a83171c299b01c Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 18 Jan 2019 15:32:04 +0200 Subject: [PATCH 40/47] update gx deps --- package.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index c925c9c..a376e24 100644 --- a/package.json +++ b/package.json @@ -7,27 +7,27 @@ "gxDependencies": [ { "author": "whyrusleeping", - "hash": "QmfZTdmunzKzAGJrSvXXQbQ5kLLUiEMX5vdwux7iXkdk7D", + "hash": "QmaoXrM4Z41PD48JY36YqQGKQpLGjyLA2cKcLsES7YddAq", "name": "go-libp2p-host", - "version": "2.1.7" + "version": "3.0.21" }, { "author": "whyrusleeping", - "hash": "QmXoz9o2PT3tEzf7hicegwex5UgVP54n3k82K7jrWFyN86", + "hash": "QmNgLg1NTw37iWbYPKcyK85YJ9Whs1MkPtJwhfqbNYAyKg", "name": "go-libp2p-net", - "version": "2.0.7" + "version": "3.0.22" }, { "author": "whyrusleeping", - "hash": "QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74", + "hash": "QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY", "name": "go-libp2p-peer", - "version": "2.3.2" + "version": "3.0.0" }, { "author": "whyrusleeping", - "hash": "QmdeiKhUy1TVGBaKxt7y1QmBDLBdisSrLJ1x58Eoj4PXUh", + "hash": "QmPiemjiKBC9VA7vZF82m4x1oygtg2c2YVqag8PX7dN1BD", "name": "go-libp2p-peerstore", - "version": "1.4.17" + "version": "2.0.13" }, { "author": "whyrusleeping", @@ -37,32 +37,32 @@ }, { "author": "multiformats", - "hash": "QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb", + "hash": "QmNTCey11oxhb1AxDnQBRHtdhap6Ctud872NjAYPYYXPuc", "name": "go-multiaddr", - "version": "1.2.6" + "version": "1.4.0" }, { - "hash": "QmTG23dvpBCBjqQwyDxV8CQT6jmS4PSftNr1VqHhE3MLy7", + "hash": "QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C", "name": "go-log", - "version": "1.4.1" + "version": "1.5.8" }, { "author": "whyrusleeping", - "hash": "QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV", + "hash": "QmdxUuburamoF6zF9qjeQC4WYcWGbWuRmdLacMEsW8ioD8", "name": "gogo-protobuf", "version": "0.0.0" }, { "author": "whyrusleeping", - "hash": "Qmc64U41EEB4nPG7wxjEqFwKJajS2f8kk5q2TvUrQf78Xu", + "hash": "QmQLbY1oKd4eHrikizXXwYkxn6yujUNSUMimv3UCaWTSWX", "name": "go-libp2p-blankhost", - "version": "0.2.7" + "version": "0.3.21" }, { "author": "whyrusleeping", - "hash": "Qmb6BsZf6Y3kxffXMNTubGPF1w1bkHtpvhfYbmnwP3NQyw", + "hash": "QmcD6i5pkzKcy5AiSEU22xmj8MYkkPSaXVvbYo7Wx2hp6H", "name": "go-libp2p-netutil", - "version": "0.3.11" + "version": "0.4.18" } ], "gxVersion": "0.12.1", From f2ee9b3d44894fdcaef2d709f199f19400f731d3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 18 Jan 2019 15:46:02 +0200 Subject: [PATCH 41/47] expose counter in register interface --- db/dbi.go | 2 +- db/sqlite/db.go | 27 ++++++++++++++++++++++----- svc.go | 6 +++--- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/db/dbi.go b/db/dbi.go index b6fe8f6..3568877 100644 --- a/db/dbi.go +++ b/db/dbi.go @@ -13,7 +13,7 @@ type RegistrationRecord struct { type DB interface { Close() error - Register(p peer.ID, ns string, addrs [][]byte, ttl int) error + Register(p peer.ID, ns string, addrs [][]byte, ttl int) (uint64, error) Unregister(p peer.ID, ns string) error CountRegistrations(p peer.ID) (int, error) Discover(ns string, cookie []byte, limit int) ([]RegistrationRecord, []byte, error) diff --git a/db/sqlite/db.go b/db/sqlite/db.go index 356ed68..1399df2 100644 --- a/db/sqlite/db.go +++ b/db/sqlite/db.go @@ -33,6 +33,7 @@ type DB struct { selectPeerRegistrationsC *sql.Stmt selectPeerRegistrationsNSC *sql.Stmt deleteExpiredRegistrations *sql.Stmt + getCounter *sql.Stmt nonce []byte @@ -189,35 +190,51 @@ func (db *DB) prepareStmts() error { } db.deleteExpiredRegistrations = stmt + stmt, err = db.db.Prepare("SELECT MAX(counter) FROM Registrations") + if err != nil { + return err + } + db.getCounter = stmt + return nil } -func (db *DB) Register(p peer.ID, ns string, addrs [][]byte, ttl int) error { +func (db *DB) Register(p peer.ID, ns string, addrs [][]byte, ttl int) (uint64, error) { pid := p.Pretty() maddrs := packAddrs(addrs) expire := time.Now().Unix() + int64(ttl) tx, err := db.db.Begin() if err != nil { - return err + return 0, err } delOld := tx.Stmt(db.deletePeerRegistrationsNs) insertNew := tx.Stmt(db.insertPeerRegistration) + getCounter := tx.Stmt(db.getCounter) _, err = delOld.Exec(pid, ns) if err != nil { tx.Rollback() - return err + return 0, err } _, err = insertNew.Exec(pid, ns, expire, maddrs) if err != nil { tx.Rollback() - return err + return 0, err } - return tx.Commit() + var counter uint64 + row := getCounter.QueryRow() + err = row.Scan(&counter) + if err != nil { + tx.Rollback() + return 0, err + } + + err = tx.Commit() + return counter, err } func (db *DB) CountRegistrations(p peer.ID) (int, error) { diff --git a/svc.go b/svc.go index 0be1f07..0293765 100644 --- a/svc.go +++ b/svc.go @@ -26,7 +26,7 @@ type RendezvousService struct { } type RendezvousSync interface { - Register(p peer.ID, ns string, addrs [][]byte, ttl int) + Register(p peer.ID, ns string, addrs [][]byte, ttl int, counter uint64) Unregister(p peer.ID, ns string) } @@ -160,7 +160,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * } // ok, seems like we can register - err = rz.DB.Register(p, ns, maddrs, ttl) + counter, err := rz.DB.Register(p, ns, maddrs, ttl) if err != nil { log.Errorf("Error registering: %s", err.Error()) return newRegisterResponseError(pb.Message_E_INTERNAL_ERROR, "database error") @@ -169,7 +169,7 @@ func (rz *RendezvousService) handleRegister(p peer.ID, m *pb.Message_Register) * log.Infof("registered peer %s %s (%d)", p, ns, ttl) for _, rzs := range rz.rzs { - rzs.Register(p, ns, maddrs, ttl) + rzs.Register(p, ns, maddrs, ttl, counter) } return newRegisterResponse(ttl) From 2843bd30d13531ee19bd2a25f17f98c35ce6f63e Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 18 Jan 2019 15:53:16 +0200 Subject: [PATCH 42/47] update tests --- db/sqlite/db_test.go | 16 ++++++++-------- package.json | 6 +++--- svc_test.go | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/db/sqlite/db_test.go b/db/sqlite/db_test.go index 20087c0..9a7b277 100644 --- a/db/sqlite/db_test.go +++ b/db/sqlite/db_test.go @@ -149,7 +149,7 @@ func TestDBRegistrationAndDiscovery(t *testing.T) { addrs2 := [][]byte{addr2.Bytes()} // register p1 and do discovery - err = db.Register(p1, "foo1", addrs1, 60) + _, err = db.Register(p1, "foo1", addrs1, 60) if err != nil { t.Fatal(err) } @@ -178,7 +178,7 @@ func TestDBRegistrationAndDiscovery(t *testing.T) { } // register p2 and do progressive discovery - err = db.Register(p2, "foo1", addrs2, 60) + _, err = db.Register(p2, "foo1", addrs2, 60) if err != nil { t.Fatal(err) } @@ -207,7 +207,7 @@ func TestDBRegistrationAndDiscovery(t *testing.T) { } // reregister p1 and do progressive discovery - err = db.Register(p1, "foo1", addrs1, 60) + _, err = db.Register(p1, "foo1", addrs1, 60) if err != nil { t.Fatal(err) } @@ -319,12 +319,12 @@ func TestDBRegistrationAndDiscoveryMultipleNS(t *testing.T) { } addrs2 := [][]byte{addr2.Bytes()} - err = db.Register(p1, "foo1", addrs1, 60) + _, err = db.Register(p1, "foo1", addrs1, 60) if err != nil { t.Fatal(err) } - err = db.Register(p1, "foo2", addrs1, 60) + _, err = db.Register(p1, "foo2", addrs1, 60) if err != nil { t.Fatal(err) } @@ -366,12 +366,12 @@ func TestDBRegistrationAndDiscoveryMultipleNS(t *testing.T) { t.Fatal("expected p1's addrs in registration") } - err = db.Register(p2, "foo1", addrs2, 60) + _, err = db.Register(p2, "foo1", addrs2, 60) if err != nil { t.Fatal(err) } - err = db.Register(p2, "foo2", addrs2, 60) + _, err = db.Register(p2, "foo2", addrs2, 60) if err != nil { t.Fatal(err) } @@ -475,7 +475,7 @@ func TestDBCleanup(t *testing.T) { } addrs1 := [][]byte{addr1.Bytes()} - err = db.Register(p1, "foo1", addrs1, 1) + _, err = db.Register(p1, "foo1", addrs1, 1) if err != nil { t.Fatal(err) } diff --git a/package.json b/package.json index a376e24..4fb1061 100644 --- a/package.json +++ b/package.json @@ -60,9 +60,9 @@ }, { "author": "whyrusleeping", - "hash": "QmcD6i5pkzKcy5AiSEU22xmj8MYkkPSaXVvbYo7Wx2hp6H", - "name": "go-libp2p-netutil", - "version": "0.4.18" + "hash": "QmegQFxhr1J6yZ1vDQuDmJi5jntmj6BL96S11HVtXNCaHb", + "name": "go-libp2p-swarm", + "version": "3.0.28" } ], "gxVersion": "0.12.1", diff --git a/svc_test.go b/svc_test.go index 7a7ed5c..d981fe7 100644 --- a/svc_test.go +++ b/svc_test.go @@ -13,9 +13,9 @@ import ( bhost "github.com/libp2p/go-libp2p-blankhost" host "github.com/libp2p/go-libp2p-host" inet "github.com/libp2p/go-libp2p-net" - netutil "github.com/libp2p/go-libp2p-netutil" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" + testutil "github.com/libp2p/go-libp2p-swarm/testing" ) func getRendezvousHosts(t *testing.T, ctx context.Context, n int) []host.Host { @@ -30,7 +30,7 @@ func getNetHosts(t *testing.T, ctx context.Context, n int) []host.Host { var out []host.Host for i := 0; i < n; i++ { - netw := netutil.GenSwarmNetwork(t, ctx) + netw := testutil.GenSwarmNetwork(t, ctx) h := bhost.NewBlankHost(netw) out = append(out, h) } From 91cdb88828f2c6d764471ae709a5b12a1eb12d08 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 28 May 2019 14:41:28 -0400 Subject: [PATCH 43/47] Switched from gx to go mod and started using go-libp2p-core interfaces --- client.go | 26 ++--- client_test.go | 6 +- db/dbi.go | 2 +- db/sqlite/db.go | 2 +- db/sqlite/db_test.go | 2 +- go.mod | 11 +++ go.sum | 228 +++++++++++++++++++++++++++++++++++++++++++ package.json | 75 -------------- proto.go | 15 ++- svc.go | 7 +- svc_test.go | 28 +++--- 11 files changed, 283 insertions(+), 119 deletions(-) create mode 100644 go.mod create mode 100644 go.sum delete mode 100644 package.json diff --git a/client.go b/client.go index 4ed8b87..09ec733 100644 --- a/client.go +++ b/client.go @@ -9,10 +9,10 @@ import ( pb "github.com/libp2p/go-libp2p-rendezvous/pb" ggio "github.com/gogo/protobuf/io" - 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" + + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" ) var ( @@ -27,7 +27,7 @@ type RendezvousPoint interface { } type Registration struct { - Peer pstore.PeerInfo + Peer peer.AddrInfo Ns string Ttl int } @@ -35,8 +35,8 @@ type Registration struct { type RendezvousClient 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, cookie []byte) ([]pstore.PeerInfo, []byte, error) - DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) + Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]peer.AddrInfo, []byte, error) + DiscoverAsync(ctx context.Context, ns string) (<-chan peer.AddrInfo, error) } func NewRendezvousPoint(host host.Host, p peer.ID) RendezvousPoint { @@ -73,7 +73,7 @@ func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) err r := ggio.NewDelimitedReader(s, inet.MessageSizeMax) w := ggio.NewDelimitedWriter(s) - req := newRegisterMessage(ns, pstore.PeerInfo{ID: rp.host.ID(), Addrs: rp.host.Addrs()}, ttl) + req := newRegisterMessage(ns, peer.AddrInfo{ID: rp.host.ID(), Addrs: rp.host.Addrs()}, ttl) err = w.WriteMsg(req) if err != nil { return err @@ -264,13 +264,13 @@ func discoverAsync(ctx context.Context, ns string, s inet.Stream, ch chan Regist } } -func (rc *rendezvousClient) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]pstore.PeerInfo, []byte, error) { +func (rc *rendezvousClient) Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]peer.AddrInfo, []byte, error) { regs, cookie, err := rc.rp.Discover(ctx, ns, limit, cookie) if err != nil { return nil, nil, err } - pinfos := make([]pstore.PeerInfo, len(regs)) + pinfos := make([]peer.AddrInfo, len(regs)) for i, reg := range regs { pinfos[i] = reg.Peer } @@ -278,18 +278,18 @@ func (rc *rendezvousClient) Discover(ctx context.Context, ns string, limit int, return pinfos, cookie, nil } -func (rc *rendezvousClient) DiscoverAsync(ctx context.Context, ns string) (<-chan pstore.PeerInfo, error) { +func (rc *rendezvousClient) DiscoverAsync(ctx context.Context, ns string) (<-chan peer.AddrInfo, error) { rch, err := rc.rp.DiscoverAsync(ctx, ns) if err != nil { return nil, err } - ch := make(chan pstore.PeerInfo) + ch := make(chan peer.AddrInfo) go discoverPeersAsync(ctx, rch, ch) return ch, nil } -func discoverPeersAsync(ctx context.Context, rch <-chan Registration, ch chan pstore.PeerInfo) { +func discoverPeersAsync(ctx context.Context, rch <-chan Registration, ch chan peer.AddrInfo) { defer close(ch) for { select { diff --git a/client_test.go b/client_test.go index 0c33200..6470932 100644 --- a/client_test.go +++ b/client_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - host "github.com/libp2p/go-libp2p-host" - pstore "github.com/libp2p/go-libp2p-peerstore" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" ) func getRendezvousClients(t *testing.T, hosts []host.Host) []RendezvousClient { @@ -110,7 +110,7 @@ func TestClientRegistrationAndDiscoveryAsync(t *testing.T) { DiscoverAsyncInterval = 2 * time.Minute } -func checkPeerInfo(t *testing.T, pi pstore.PeerInfo, host host.Host) { +func checkPeerInfo(t *testing.T, pi peer.AddrInfo, host host.Host) { if pi.ID != host.ID() { t.Fatal("bad registration: peer ID doesn't match host ID") } diff --git a/db/dbi.go b/db/dbi.go index 3568877..4da1810 100644 --- a/db/dbi.go +++ b/db/dbi.go @@ -1,7 +1,7 @@ package dbi import ( - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" ) type RegistrationRecord struct { diff --git a/db/sqlite/db.go b/db/sqlite/db.go index 1399df2..3b05791 100644 --- a/db/sqlite/db.go +++ b/db/sqlite/db.go @@ -16,7 +16,7 @@ import ( _ "github.com/mattn/go-sqlite3" logging "github.com/ipfs/go-log" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" ) var log = logging.Logger("rendezvous/db") diff --git a/db/sqlite/db_test.go b/db/sqlite/db_test.go index 9a7b277..c498d83 100644 --- a/db/sqlite/db_test.go +++ b/db/sqlite/db_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - peer "github.com/libp2p/go-libp2p-peer" + "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" ) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e0aaab4 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/libp2p/go-libp2p-rendezvous + +require ( + github.com/gogo/protobuf v1.2.1 + github.com/ipfs/go-log v0.0.1 + github.com/libp2p/go-libp2p-blankhost v0.1.1 + github.com/libp2p/go-libp2p-core v0.0.1 + github.com/libp2p/go-libp2p-swarm v0.1.0 + github.com/mattn/go-sqlite3 v1.10.0 + github.com/multiformats/go-multiaddr v0.0.4 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6bd3d2b --- /dev/null +++ b/go.sum @@ -0,0 +1,228 @@ +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +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/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/snappy-go v0.0.0-20151229074030-0bdef8d06723/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/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +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 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +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 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8 h1:bspPhN+oKYFk5fcGNuQzp6IGzYQSenLEgH3s6jkXrWw= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/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.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1 h1:9Rrn/H46cXjaA2HQ5Y8lyhOS1NhTkZ4yuEs2r3Eechg= +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.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-flow-metrics v0.0.1 h1:0gxuFd2GuK7IIP5pKljLwps6TvcuYgvG7Atqi3INF5s= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-libp2p-blankhost v0.1.1 h1:X919sCh+KLqJcNRApj43xCSiQRYqOSI88Fdf55ngf78= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-core v0.0.1 h1:HSTZtFIq/W5Ue43Zw+uWZyy2Vl5WtF0zDjKN8/DT/1I= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0 h1:MKh7pRNPHSh1fLPj8u/M/s/napdmeNpoi9BRy9lPN0E= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-secio v0.1.0 h1:NNP5KLxuP97sE5Bu3iuwOWyT/dKEGMN5zSLMWdB7GTQ= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-swarm v0.1.0 h1:HrFk2p0awrGEgch9JXK/qp/hfjqQfgNxpLWnCiWPg5s= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3 h1:bdij4bKaaND7tCsaXVjRfYkMpvoOeKj9AVQGJllA6jM= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0 h1:TSPZ5cMMz/wdoYsye/wU1TE4G3LDGMoeEN0xgnCKU/I= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-maddr-filter v0.0.4 h1:hx8HIuuwk34KePddrp2mM5ivgPkZ09JH4AvsALRbFUs= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.2 h1:ivPvEKHxmVkTClHzg6RXTYHqaJQ0V9cDbq+6lKb3UV0= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1 h1:Ce6e2Pyu+b5MC1k3eeFtAax0pW4gc6MosYSLV05UeLw= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0 h1:IGhowvEqyMFknOar4FWCKSWE0zL36UFKQtiRQD60/8o= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-yamux v1.2.2 h1:s6J6o7+ajoQMjHe7BEnq+EynOj5D2EoG8CuQgL3F2vg= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +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 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= +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 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1 h1:OJIdWOWYe2l5PQNgimGtuwHY8nDskvJ5vvs//YnzRLs= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= +github.com/mr-tron/base58 v1.1.2/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-multiaddr v0.0.1 h1:/QUV3VBMDI6pi6xfiw7lr6xhDWWvQKn9udPn68kLSdY= +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 h1:WgMSI84/eRLdbptXMkMWDXPjPq7SPLIgGUVm2eroyU4= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr-dns v0.0.1 h1:jQt9c6tDSdQLIlBo4tXYx7QUHCPjxsB1zXcag/2S7zc= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2 h1:/Bbsgsy3R6e3jf2qBahzNHzww6usYaZ0NhNH3sqdFS8= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-fmt v0.0.1 h1:5YjeOIzbX8OTKVaN72aOzGIYW7PnrZrnkDyOfAWRSMA= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-net v0.0.1 h1:76O59E3FavvHqNg7jvzWzsPSW5JSi/ek0E4eiDVbg9g= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1 h1:HHwN1K12I+XllBCrqKnhX949Orn4oawPkegHMu2vDqQ= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5 h1:1wxmCvTXAifAepIMyF39vZinRw5sbqjPs/UIi93+uik= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.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/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a h1:/eS3yfGjQKG+9kayBkj0ip1BGhq6zJ3eaVksphxAaek= +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 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +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 h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +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= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/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 h1:+/WWzjwW6gidDJnMKWLKLX1gxn7irUTF1fLpQovfQ5M= +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-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTdvMUC/cFajkphs1YLQo= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +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 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/package.json b/package.json deleted file mode 100644 index 4fb1061..0000000 --- a/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "author": "vyzo", - "bugs": {}, - "gx": { - "dvcsimport": "github.com/libp2p/go-libp2p-rendezvous" - }, - "gxDependencies": [ - { - "author": "whyrusleeping", - "hash": "QmaoXrM4Z41PD48JY36YqQGKQpLGjyLA2cKcLsES7YddAq", - "name": "go-libp2p-host", - "version": "3.0.21" - }, - { - "author": "whyrusleeping", - "hash": "QmNgLg1NTw37iWbYPKcyK85YJ9Whs1MkPtJwhfqbNYAyKg", - "name": "go-libp2p-net", - "version": "3.0.22" - }, - { - "author": "whyrusleeping", - "hash": "QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY", - "name": "go-libp2p-peer", - "version": "3.0.0" - }, - { - "author": "whyrusleeping", - "hash": "QmPiemjiKBC9VA7vZF82m4x1oygtg2c2YVqag8PX7dN1BD", - "name": "go-libp2p-peerstore", - "version": "2.0.13" - }, - { - "author": "whyrusleeping", - "hash": "QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN", - "name": "go-libp2p-protocol", - "version": "1.0.0" - }, - { - "author": "multiformats", - "hash": "QmNTCey11oxhb1AxDnQBRHtdhap6Ctud872NjAYPYYXPuc", - "name": "go-multiaddr", - "version": "1.4.0" - }, - { - "hash": "QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C", - "name": "go-log", - "version": "1.5.8" - }, - { - "author": "whyrusleeping", - "hash": "QmdxUuburamoF6zF9qjeQC4WYcWGbWuRmdLacMEsW8ioD8", - "name": "gogo-protobuf", - "version": "0.0.0" - }, - { - "author": "whyrusleeping", - "hash": "QmQLbY1oKd4eHrikizXXwYkxn6yujUNSUMimv3UCaWTSWX", - "name": "go-libp2p-blankhost", - "version": "0.3.21" - }, - { - "author": "whyrusleeping", - "hash": "QmegQFxhr1J6yZ1vDQuDmJi5jntmj6BL96S11HVtXNCaHb", - "name": "go-libp2p-swarm", - "version": "3.0.28" - } - ], - "gxVersion": "0.12.1", - "language": "go", - "license": "MIT", - "name": "go-libp2p-rendezvous", - "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "0.0.0" -} - diff --git a/proto.go b/proto.go index 9ae60f2..6e4237f 100644 --- a/proto.go +++ b/proto.go @@ -8,9 +8,8 @@ import ( pb "github.com/libp2p/go-libp2p-rendezvous/pb" logging "github.com/ipfs/go-log" - peer "github.com/libp2p/go-libp2p-peer" - pstore "github.com/libp2p/go-libp2p-peerstore" - protocol "github.com/libp2p/go-libp2p-protocol" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" ma "github.com/multiformats/go-multiaddr" ) @@ -31,7 +30,7 @@ func (e RendezvousError) Error() string { return fmt.Sprintf("Rendezvous error: %s (%s)", e.Text, pb.Message_ResponseStatus(e.Status).String()) } -func newRegisterMessage(ns string, pi pstore.PeerInfo, ttl int) *pb.Message { +func newRegisterMessage(ns string, pi peer.AddrInfo, ttl int) *pb.Message { msg := new(pb.Message) msg.Type = pb.Message_REGISTER.Enum() msg.Register = new(pb.Message_Register) @@ -79,14 +78,14 @@ func newDiscoverMessage(ns string, limit int, cookie []byte) *pb.Message { return msg } -func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) { +func pbToPeerInfo(p *pb.Message_PeerInfo) (peer.AddrInfo, error) { if p == nil { - return pstore.PeerInfo{}, errors.New("missing peer info") + return peer.AddrInfo{}, errors.New("missing peer info") } id, err := peer.IDFromBytes(p.Id) if err != nil { - return pstore.PeerInfo{}, err + return peer.AddrInfo{}, err } addrs := make([]ma.Multiaddr, 0, len(p.Addrs)) for _, bs := range p.Addrs { @@ -98,7 +97,7 @@ func pbToPeerInfo(p *pb.Message_PeerInfo) (pstore.PeerInfo, error) { addrs = append(addrs, addr) } - return pstore.PeerInfo{ID: id, Addrs: addrs}, nil + return peer.AddrInfo{ID: id, Addrs: addrs}, nil } func newRegisterResponse(ttl int) *pb.Message_RegisterResponse { diff --git a/svc.go b/svc.go index 0293765..e7204b1 100644 --- a/svc.go +++ b/svc.go @@ -7,9 +7,10 @@ import ( pb "github.com/libp2p/go-libp2p-rendezvous/pb" ggio "github.com/gogo/protobuf/io" - host "github.com/libp2p/go-libp2p-host" - inet "github.com/libp2p/go-libp2p-net" - peer "github.com/libp2p/go-libp2p-peer" + + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" ) const ( diff --git a/svc_test.go b/svc_test.go index d981fe7..eaea97d 100644 --- a/svc_test.go +++ b/svc_test.go @@ -11,10 +11,10 @@ import ( ggio "github.com/gogo/protobuf/io" bhost "github.com/libp2p/go-libp2p-blankhost" - 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" + + "github.com/libp2p/go-libp2p-core/host" + inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" testutil "github.com/libp2p/go-libp2p-swarm/testing" ) @@ -30,7 +30,7 @@ func getNetHosts(t *testing.T, ctx context.Context, n int) []host.Host { var out []host.Host for i := 0; i < n; i++ { - netw := testutil.GenSwarmNetwork(t, ctx) + netw := testutil.GenSwarm(t, ctx) h := bhost.NewBlankHost(netw) out = append(out, h) } @@ -187,7 +187,7 @@ func TestSVCErrors(t *testing.T) { // testable registration errors res, err := doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("", pstore.PeerInfo{}, 0)) + newRegisterMessage("", peer.AddrInfo{}, 0)) if err != nil { t.Fatal(err) } @@ -198,7 +198,7 @@ func TestSVCErrors(t *testing.T) { badns := make([]byte, 2*MaxNamespaceLength) rand.Read(badns) res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage(string(badns), pstore.PeerInfo{}, 0)) + newRegisterMessage(string(badns), peer.AddrInfo{}, 0)) if err != nil { t.Fatal(err) } @@ -207,7 +207,7 @@ func TestSVCErrors(t *testing.T) { } res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{}, 0)) + newRegisterMessage("foo", peer.AddrInfo{}, 0)) if err != nil { t.Fatal(err) } @@ -216,7 +216,7 @@ func TestSVCErrors(t *testing.T) { } res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{ID: peer.ID("blah")}, 0)) + newRegisterMessage("foo", peer.AddrInfo{ID: peer.ID("blah")}, 0)) if err != nil { t.Fatal(err) } @@ -230,7 +230,7 @@ func TestSVCErrors(t *testing.T) { } res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{ID: p}, 0)) + newRegisterMessage("foo", peer.AddrInfo{ID: p}, 0)) if err != nil { t.Fatal(err) } @@ -239,7 +239,7 @@ func TestSVCErrors(t *testing.T) { } res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID()}, 0)) + newRegisterMessage("foo", peer.AddrInfo{ID: hosts[1].ID()}, 0)) if err != nil { t.Fatal(err) } @@ -248,7 +248,7 @@ func TestSVCErrors(t *testing.T) { } res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 2*MaxTTL)) + newRegisterMessage("foo", peer.AddrInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 2*MaxTTL)) if err != nil { t.Fatal(err) } @@ -260,7 +260,7 @@ func TestSVCErrors(t *testing.T) { for i := 0; i < MaxRegistrations+1; i++ { ns := fmt.Sprintf("foo%d", i) res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage(ns, pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) + newRegisterMessage(ns, peer.AddrInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) if err != nil { t.Fatal(err) } @@ -270,7 +270,7 @@ func TestSVCErrors(t *testing.T) { } // and now fail res, err = doTestRequest(ctx, hosts[1], hosts[0].ID(), - newRegisterMessage("foo", pstore.PeerInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) + newRegisterMessage("foo", peer.AddrInfo{ID: hosts[1].ID(), Addrs: hosts[1].Addrs()}, 0)) if err != nil { t.Fatal(err) } From 790128061ee519ba87791500e1e2be26e36b42a9 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 31 May 2019 12:48:51 -0400 Subject: [PATCH 44/47] Add stateful discovery client --- discovery_client.go | 134 ++++++++++++++++++++++++++++++++ discovery_client_test.go | 163 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 discovery_client.go create mode 100644 discovery_client_test.go diff --git a/discovery_client.go b/discovery_client.go new file mode 100644 index 0000000..3a25253 --- /dev/null +++ b/discovery_client.go @@ -0,0 +1,134 @@ +package rendezvous + +import ( + "context" + "github.com/libp2p/go-libp2p-core/discovery" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "math" + "math/rand" + "sync" + "time" +) + +type rendezvousDiscoveryClient struct { + rp RendezvousPoint + peerCache sync.Map //is a map[string]discoveredPeerCache + rng *rand.Rand + rngMux sync.Mutex +} + +type discoveredPeerCache struct { + cachedRegs []Registration + mux sync.Mutex +} + +func NewRendezvousDiscoveryClient(host host.Host, rendezvousPeer peer.ID) discovery.Discovery { + rp := NewRendezvousPoint(host, rendezvousPeer) + return &rendezvousDiscoveryClient{rp, sync.Map{}, rand.New(rand.NewSource(rand.Int63())), sync.Mutex{}} +} + +func (c *rendezvousDiscoveryClient) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) { + // Get options + var options discovery.Options + err := options.Apply(opts...) + if err != nil { + return 0, err + } + + ttl := options.Ttl + var ttlSeconds int + + // Default is minimum duration + if ttl == 0 { + ttlSeconds = 120 + } else { + ttlSeconds = int(math.Round(ttl.Seconds())) + } + + if err := c.rp.Register(ctx, ns, ttlSeconds); err != nil { + return 0, err + } + + actualTTL := time.Duration(ttlSeconds) * time.Second + return actualTTL, nil +} + +func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) { + // Get options + var options discovery.Options + err := options.Apply(opts...) + if err != nil { + return nil, err + } + + const maxLimit = 1000 + limit := options.Limit + if limit == 0 || limit > maxLimit { + limit = maxLimit + } + + // Get cached peers + var cache *discoveredPeerCache + + genericCache, _ := c.peerCache.LoadOrStore(ns, &discoveredPeerCache{}) + cache = genericCache.(*discoveredPeerCache) + + cache.mux.Lock() + cachedRegs := cache.cachedRegs + + // Remove all expired entries from cache + currentTime := int(time.Now().Unix()) + newCacheSize := len(cachedRegs) + + for i := 0; i < newCacheSize; i++ { + reg := cachedRegs[i] + if reg.Ttl < currentTime { + newCacheSize-- + if i != newCacheSize { + cachedRegs[i] = cachedRegs[newCacheSize] + i-- + } + } + } + cache.cachedRegs = cachedRegs[:newCacheSize] + cache.mux.Unlock() + + // Discover new records if we don't have enough + var discoveryErr error + if newCacheSize < limit { + if discoveryRecords, _, err := c.rp.Discover(ctx, ns, limit, nil); err == nil { + for i := range discoveryRecords { + discoveryRecords[i].Ttl += currentTime + } + cache.mux.Lock() + cache.cachedRegs = discoveryRecords + cache.mux.Unlock() + } else { + // TODO: Should we return error even if we have valid cached results? + discoveryErr = err + } + } + + // Randomize and fill channel with available records + cache.mux.Lock() + cachedRegs = cache.cachedRegs + sendQuantity := len(cachedRegs) + if limit < sendQuantity { + sendQuantity = limit + } + + chPeer := make(chan peer.AddrInfo, sendQuantity) + + c.rngMux.Lock() + perm := c.rng.Perm(len(cachedRegs))[0:sendQuantity] + c.rngMux.Unlock() + + for _, i := range perm { + chPeer <- cachedRegs[i].Peer + } + + cache.mux.Unlock() + close(chPeer) + return chPeer, discoveryErr +} diff --git a/discovery_client_test.go b/discovery_client_test.go new file mode 100644 index 0000000..854737e --- /dev/null +++ b/discovery_client_test.go @@ -0,0 +1,163 @@ +package rendezvous + +import ( + "context" + "github.com/libp2p/go-libp2p-core/discovery" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "math/rand" + "sync" + "testing" + "time" +) + +func getRendezvousDiscovery(hosts []host.Host) []discovery.Discovery { + clients := make([]discovery.Discovery, len(hosts)-1) + rendezvousPeer := hosts[0].ID() + for i, h := range hosts[1:] { + rp := NewRendezvousPoint(h, rendezvousPeer) + rng := rand.New(rand.NewSource(int64(i))) + clients[i] = &rendezvousDiscoveryClient{rp: rp, peerCache: sync.Map{}, rng: rng} + } + return clients +} + +func peerChannelToArray(pch <-chan peer.AddrInfo) []peer.AddrInfo { + pi := make([]peer.AddrInfo, len(pch)) + peerIndex := 0 + for p := range pch { + pi[peerIndex] = p + peerIndex++ + } + return pi +} + +func checkAvailablePeers(t *testing.T, ctx context.Context, client discovery.Discovery, namespace string, expectedNumPeers int) { + pch, err := client.FindPeers(ctx, namespace) + if err != nil { + t.Fatal(err) + } + + pi := peerChannelToArray(pch) + + if len(pi) != expectedNumPeers { + t.Fatalf("Expected %d peers", expectedNumPeers) + } +} + +func TestDiscoveryClientAdvertiseAndFindPeers(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Define parameters + const namespace = "foo1" + const numClients = 4 + const ttl = DefaultTTL * time.Second + + // Instantiate server and clients + hosts := getRendezvousHosts(t, ctx, numClients+1) + + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + + clients := getRendezvousDiscovery(hosts) + + // Advertise and check one peer + _, err = clients[0].Advertise(ctx, namespace, discovery.TTL(ttl)) + if err != nil { + t.Fatal(err) + } + + checkAvailablePeers(t, ctx, clients[0], namespace, 1) + + // Advertise and check the rest of the peers incrementally + for i, client := range clients[1:] { + if _, err = client.Advertise(ctx, namespace, discovery.TTL(ttl)); err != nil { + t.Fatal(err) + } + + checkAvailablePeers(t, ctx, client, namespace, i+2) + } + + // Check that the first peer can get all the new records + checkAvailablePeers(t, ctx, clients[0], namespace, numClients) +} + +func TestDiscoveryClientExpiredCachedRecords(t *testing.T) { + BaseDiscoveryClientCacheExpirationTest(t, true) +} + +func TestDiscoveryClientExpiredManyCachedRecords(t *testing.T) { + BaseDiscoveryClientCacheExpirationTest(t, false) +} + +func BaseDiscoveryClientCacheExpirationTest(t *testing.T, onlyRequestFromCache bool) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Define parameters + const numShortLivedRegs = 5 + const everyIthRegIsLongTTL = 2 + const numBaseRegs = numShortLivedRegs * everyIthRegIsLongTTL + const namespace = "foo1" + const longTTL = DefaultTTL * time.Second + const shortTTL = 2 * time.Second + + // Instantiate server and clients + hosts := getRendezvousHosts(t, ctx, numBaseRegs+3) + + svc, err := makeRendezvousService(ctx, hosts[0], ":memory:") + if err != nil { + t.Fatal(err) + } + defer svc.DB.Close() + clients := getRendezvousDiscovery(hosts) + + // Advertise most clients + for i, client := range clients[2:] { + ttl := shortTTL + if i%everyIthRegIsLongTTL == 0 { + ttl = longTTL + } + + if _, err = client.Advertise(ctx, namespace, discovery.TTL(ttl)); err != nil { + t.Fatal(err) + } + } + + // Find peers from an unrelated client (results should be cached) + pch, err := clients[0].FindPeers(ctx, namespace) + if err != nil { + t.Fatal(err) + } + pi := peerChannelToArray(pch) + if len(pi) != numBaseRegs { + t.Fatalf("expected %d registrations", numBaseRegs) + } + + // Advertise from a new unrelated peer + if _, err := clients[1].Advertise(ctx, namespace, discovery.TTL(longTTL)); err != nil { + t.Fatal(err) + } + + // Wait for cache expiration + time.Sleep(shortTTL + time.Second) + + // Check if number of retrieved records matches caching expectations after expiration + expectedNumClients := numShortLivedRegs + if !onlyRequestFromCache { + expectedNumClients++ + } + pch, err = clients[0].FindPeers(ctx, namespace, discovery.Limit(expectedNumClients)) + if err != nil { + t.Fatal(err) + } + pi = peerChannelToArray(pch) + + if len(pi) != expectedNumClients { + t.Fatalf("received an incorrect number of records: %d", len(pi)) + } +} From 9052b531ccde1f19af23557adba08bd59c0e76f4 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 31 May 2019 18:58:46 -0400 Subject: [PATCH 45/47] RendezvousPoint and RendezvousClient now return the server's TTL on Registered records. Default TTL for discovery client increased discovery client now utilizes server cookie for added efficiency --- client.go | 29 ++++++++++---------- discovery_client.go | 66 +++++++++++++++++++++++++++------------------ 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/client.go b/client.go index 09ec733..e416433 100644 --- a/client.go +++ b/client.go @@ -20,7 +20,7 @@ var ( ) type RendezvousPoint interface { - Register(ctx context.Context, ns string, ttl int) error + Register(ctx context.Context, ns string, ttl int) (time.Duration, error) Unregister(ctx context.Context, ns string) error Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]Registration, []byte, error) DiscoverAsync(ctx context.Context, ns string) (<-chan Registration, error) @@ -33,7 +33,7 @@ type Registration struct { } type RendezvousClient interface { - Register(ctx context.Context, ns string, ttl int) error + Register(ctx context.Context, ns string, ttl int) (time.Duration, error) Unregister(ctx context.Context, ns string) error Discover(ctx context.Context, ns string, limit int, cookie []byte) ([]peer.AddrInfo, []byte, error) DiscoverAsync(ctx context.Context, ns string) (<-chan peer.AddrInfo, error) @@ -63,7 +63,7 @@ type rendezvousClient struct { rp RendezvousPoint } -func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) error { +func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) (time.Duration, error) { s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { return err @@ -76,39 +76,40 @@ func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) err req := newRegisterMessage(ns, peer.AddrInfo{ID: rp.host.ID(), Addrs: rp.host.Addrs()}, ttl) err = w.WriteMsg(req) if err != nil { - return err + return 0, err } var res pb.Message err = r.ReadMsg(&res) if err != nil { - return err + return 0, err } if res.GetType() != pb.Message_REGISTER_RESPONSE { - return fmt.Errorf("Unexpected response: %s", res.GetType().String()) + return 0, fmt.Errorf("Unexpected response: %s", res.GetType().String()) } - status := res.GetRegisterResponse().GetStatus() + response := res.GetRegisterResponse() + status := response.GetStatus() if status != pb.Message_OK { - return RendezvousError{Status: status, Text: res.GetRegisterResponse().GetStatusText()} + return 0, RendezvousError{Status: status, Text: res.GetRegisterResponse().GetStatusText()} } - return nil + return time.Duration(*response.Ttl) * time.Second, nil } -func (rc *rendezvousClient) Register(ctx context.Context, ns string, ttl int) error { +func (rc *rendezvousClient) Register(ctx context.Context, ns string, ttl int) (time.Duration, error) { if ttl < 120 { - return fmt.Errorf("registration TTL is too short") + return 0, fmt.Errorf("registration TTL is too short") } - err := rc.rp.Register(ctx, ns, ttl) + returnedTTL, err := rc.rp.Register(ctx, ns, ttl) if err != nil { - return err + return 0, err } go registerRefresh(ctx, rc.rp, ns, ttl) - return nil + return returnedTTL, nil } func registerRefresh(ctx context.Context, rz RendezvousPoint, ns string, ttl int) { diff --git a/discovery_client.go b/discovery_client.go index 3a25253..30b9ffd 100644 --- a/discovery_client.go +++ b/discovery_client.go @@ -19,7 +19,8 @@ type rendezvousDiscoveryClient struct { } type discoveredPeerCache struct { - cachedRegs []Registration + cachedRegs map[peer.ID]*Registration + cookie []byte mux sync.Mutex } @@ -39,19 +40,17 @@ func (c *rendezvousDiscoveryClient) Advertise(ctx context.Context, ns string, op ttl := options.Ttl var ttlSeconds int - // Default is minimum duration if ttl == 0 { - ttlSeconds = 120 + ttlSeconds = 7200 } else { ttlSeconds = int(math.Round(ttl.Seconds())) } - if err := c.rp.Register(ctx, ns, ttlSeconds); err != nil { + if returnedTTL, err := c.rp.Register(ctx, ns, ttlSeconds); err != nil { return 0, err + } else { + return returnedTTL, nil } - - actualTTL := time.Duration(ttlSeconds) * time.Second - return actualTTL, nil } func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) { @@ -75,34 +74,36 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op cache = genericCache.(*discoveredPeerCache) cache.mux.Lock() - cachedRegs := cache.cachedRegs // Remove all expired entries from cache currentTime := int(time.Now().Unix()) - newCacheSize := len(cachedRegs) + newCacheSize := len(cache.cachedRegs) - for i := 0; i < newCacheSize; i++ { - reg := cachedRegs[i] + for p := range cache.cachedRegs { + reg := cache.cachedRegs[p] if reg.Ttl < currentTime { newCacheSize-- - if i != newCacheSize { - cachedRegs[i] = cachedRegs[newCacheSize] - i-- - } + delete(cache.cachedRegs, p) } } - cache.cachedRegs = cachedRegs[:newCacheSize] + + cookie := cache.cookie cache.mux.Unlock() // Discover new records if we don't have enough var discoveryErr error if newCacheSize < limit { - if discoveryRecords, _, err := c.rp.Discover(ctx, ns, limit, nil); err == nil { - for i := range discoveryRecords { - discoveryRecords[i].Ttl += currentTime - } + if discoveryRecords, newCookie, err := c.rp.Discover(ctx, ns, limit, cookie); err == nil { cache.mux.Lock() - cache.cachedRegs = discoveryRecords + if cache.cachedRegs == nil { + cache.cachedRegs = make(map[peer.ID]*Registration) + } + for i := range discoveryRecords { + rec := &discoveryRecords[i] + rec.Ttl += currentTime + cache.cachedRegs[rec.Peer.ID] = rec + } + cache.cookie = newCookie cache.mux.Unlock() } else { // TODO: Should we return error even if we have valid cached results? @@ -112,8 +113,7 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op // Randomize and fill channel with available records cache.mux.Lock() - cachedRegs = cache.cachedRegs - sendQuantity := len(cachedRegs) + sendQuantity := len(cache.cachedRegs) if limit < sendQuantity { sendQuantity = limit } @@ -121,11 +121,25 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op chPeer := make(chan peer.AddrInfo, sendQuantity) c.rngMux.Lock() - perm := c.rng.Perm(len(cachedRegs))[0:sendQuantity] + perm := c.rng.Perm(len(cache.cachedRegs))[0:sendQuantity] c.rngMux.Unlock() - for _, i := range perm { - chPeer <- cachedRegs[i].Peer + permSet := make(map[int]int) + for i, v := range perm { + permSet[v] = i + } + + sendLst := make([]*peer.AddrInfo, sendQuantity) + iter := 0 + for k := range cache.cachedRegs { + if sendIndex, ok := permSet[iter]; ok { + sendLst[sendIndex] = &cache.cachedRegs[k].Peer + } + iter++ + } + + for _, send := range sendLst { + chPeer <- *send } cache.mux.Unlock() From 25d0082f0587f7f7c083fa444079c33dffe48e92 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 5 Jun 2019 13:44:44 -0400 Subject: [PATCH 46/47] fixed compile error from previous commit + code refactoring --- client.go | 4 +- client_test.go | 15 +++- discovery_client.go => discovery.go | 75 +++++++++---------- discovery_client_test.go => discovery_test.go | 2 +- svc_test.go | 12 ++- 5 files changed, 62 insertions(+), 46 deletions(-) rename discovery_client.go => discovery.go (52%) rename discovery_client_test.go => discovery_test.go (98%) diff --git a/client.go b/client.go index e416433..6cd091b 100644 --- a/client.go +++ b/client.go @@ -66,7 +66,7 @@ type rendezvousClient struct { func (rp *rendezvousPoint) Register(ctx context.Context, ns string, ttl int) (time.Duration, error) { s, err := rp.host.NewStream(ctx, rp.p, RendezvousProto) if err != nil { - return err + return 0, err } defer s.Close() @@ -134,7 +134,7 @@ func registerRefresh(ctx context.Context, rz RendezvousPoint, ns string, ttl int return } - err := rz.Register(ctx, ns, ttl) + _, err := rz.Register(ctx, ns, ttl) if err != nil { log.Errorf("Error registering [%s]: %s", ns, err.Error()) errcount++ diff --git a/client_test.go b/client_test.go index 6470932..db974b7 100644 --- a/client_test.go +++ b/client_test.go @@ -31,10 +31,13 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { clients := getRendezvousClients(t, hosts) - err = clients[0].Register(ctx, "foo1", DefaultTTL) + recordTTL, err := clients[0].Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } + if recordTTL != DefaultTTL*time.Second { + t.Fatalf("Expected record TTL to be %d seconds", DefaultTTL) + } pi, cookie, err := clients[0].Discover(ctx, "foo1", 0, nil) if err != nil { @@ -46,10 +49,13 @@ func TestClientRegistrationAndDiscovery(t *testing.T) { checkPeerInfo(t, pi[0], hosts[1]) for i, client := range clients[1:] { - err = client.Register(ctx, "foo1", DefaultTTL) + recordTTL, err = client.Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } + if recordTTL != DefaultTTL*time.Second { + t.Fatalf("Expected record TTL to be %d seconds", DefaultTTL) + } pi, cookie, err = clients[0].Discover(ctx, "foo1", 10, cookie) if err != nil { @@ -98,10 +104,13 @@ func TestClientRegistrationAndDiscoveryAsync(t *testing.T) { } for i, client := range clients[0:] { - err = client.Register(ctx, "foo1", DefaultTTL) + recordTTL, err := client.Register(ctx, "foo1", DefaultTTL) if err != nil { t.Fatal(err) } + if recordTTL != DefaultTTL*time.Second { + t.Fatalf("Expected record TTL to be %d seconds", DefaultTTL) + } pi := <-ch checkPeerInfo(t, pi, hosts[1+i]) diff --git a/discovery_client.go b/discovery.go similarity index 52% rename from discovery_client.go rename to discovery.go index 30b9ffd..94cac73 100644 --- a/discovery_client.go +++ b/discovery.go @@ -11,7 +11,7 @@ import ( "time" ) -type rendezvousDiscoveryClient struct { +type rendezvousDiscovery struct { rp RendezvousPoint peerCache sync.Map //is a map[string]discoveredPeerCache rng *rand.Rand @@ -19,17 +19,22 @@ type rendezvousDiscoveryClient struct { } type discoveredPeerCache struct { - cachedRegs map[peer.ID]*Registration + cachedRecs map[peer.ID]*record cookie []byte mux sync.Mutex } -func NewRendezvousDiscoveryClient(host host.Host, rendezvousPeer peer.ID) discovery.Discovery { - rp := NewRendezvousPoint(host, rendezvousPeer) - return &rendezvousDiscoveryClient{rp, sync.Map{}, rand.New(rand.NewSource(rand.Int63())), sync.Mutex{}} +type record struct { + peer peer.AddrInfo + expire int64 } -func (c *rendezvousDiscoveryClient) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) { +func NewRendezvousDiscovery(host host.Host, rendezvousPeer peer.ID) discovery.Discovery { + rp := NewRendezvousPoint(host, rendezvousPeer) + return &rendezvousDiscovery{rp, sync.Map{}, rand.New(rand.NewSource(rand.Int63())), sync.Mutex{}} +} + +func (c *rendezvousDiscovery) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) { // Get options var options discovery.Options err := options.Apply(opts...) @@ -53,7 +58,7 @@ func (c *rendezvousDiscoveryClient) Advertise(ctx context.Context, ns string, op } } -func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) { +func (c *rendezvousDiscovery) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) { // Get options var options discovery.Options err := options.Apply(opts...) @@ -74,54 +79,49 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op cache = genericCache.(*discoveredPeerCache) cache.mux.Lock() + defer cache.mux.Unlock() // Remove all expired entries from cache - currentTime := int(time.Now().Unix()) - newCacheSize := len(cache.cachedRegs) + currentTime := time.Now().Unix() + newCacheSize := len(cache.cachedRecs) - for p := range cache.cachedRegs { - reg := cache.cachedRegs[p] - if reg.Ttl < currentTime { + for p := range cache.cachedRecs { + rec := cache.cachedRecs[p] + if rec.expire < currentTime { newCacheSize-- - delete(cache.cachedRegs, p) + delete(cache.cachedRecs, p) } } cookie := cache.cookie - cache.mux.Unlock() // Discover new records if we don't have enough - var discoveryErr error if newCacheSize < limit { - if discoveryRecords, newCookie, err := c.rp.Discover(ctx, ns, limit, cookie); err == nil { - cache.mux.Lock() - if cache.cachedRegs == nil { - cache.cachedRegs = make(map[peer.ID]*Registration) + // TODO: Should we return error even if we have valid cached results? + var regs []Registration + var newCookie []byte + if regs, newCookie, err = c.rp.Discover(ctx, ns, limit, cookie); err == nil { + if cache.cachedRecs == nil { + cache.cachedRecs = make(map[peer.ID]*record) } - for i := range discoveryRecords { - rec := &discoveryRecords[i] - rec.Ttl += currentTime - cache.cachedRegs[rec.Peer.ID] = rec + for _, reg := range regs { + rec := &record{peer: reg.Peer, expire: int64(reg.Ttl) + currentTime} + cache.cachedRecs[rec.peer.ID] = rec } cache.cookie = newCookie - cache.mux.Unlock() - } else { - // TODO: Should we return error even if we have valid cached results? - discoveryErr = err } } // Randomize and fill channel with available records - cache.mux.Lock() - sendQuantity := len(cache.cachedRegs) - if limit < sendQuantity { - sendQuantity = limit + count := len(cache.cachedRecs) + if limit < count { + count = limit } - chPeer := make(chan peer.AddrInfo, sendQuantity) + chPeer := make(chan peer.AddrInfo, count) c.rngMux.Lock() - perm := c.rng.Perm(len(cache.cachedRegs))[0:sendQuantity] + perm := c.rng.Perm(len(cache.cachedRecs))[0:count] c.rngMux.Unlock() permSet := make(map[int]int) @@ -129,11 +129,11 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op permSet[v] = i } - sendLst := make([]*peer.AddrInfo, sendQuantity) + sendLst := make([]*peer.AddrInfo, count) iter := 0 - for k := range cache.cachedRegs { + for k := range cache.cachedRecs { if sendIndex, ok := permSet[iter]; ok { - sendLst[sendIndex] = &cache.cachedRegs[k].Peer + sendLst[sendIndex] = &cache.cachedRecs[k].peer } iter++ } @@ -142,7 +142,6 @@ func (c *rendezvousDiscoveryClient) FindPeers(ctx context.Context, ns string, op chPeer <- *send } - cache.mux.Unlock() close(chPeer) - return chPeer, discoveryErr + return chPeer, err } diff --git a/discovery_client_test.go b/discovery_test.go similarity index 98% rename from discovery_client_test.go rename to discovery_test.go index 854737e..4091ef7 100644 --- a/discovery_client_test.go +++ b/discovery_test.go @@ -17,7 +17,7 @@ func getRendezvousDiscovery(hosts []host.Host) []discovery.Discovery { for i, h := range hosts[1:] { rp := NewRendezvousPoint(h, rendezvousPeer) rng := rand.New(rand.NewSource(int64(i))) - clients[i] = &rendezvousDiscoveryClient{rp: rp, peerCache: sync.Map{}, rng: rng} + clients[i] = &rendezvousDiscovery{rp: rp, peerCache: sync.Map{}, rng: rng} } return clients } diff --git a/svc_test.go b/svc_test.go index eaea97d..cc311d1 100644 --- a/svc_test.go +++ b/svc_test.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" "testing" + "time" db "github.com/libp2p/go-libp2p-rendezvous/db/sqlite" pb "github.com/libp2p/go-libp2p-rendezvous/pb" @@ -77,10 +78,14 @@ func TestSVCRegistrationAndDiscovery(t *testing.T) { clients := getRendezvousPoints(t, hosts) - err = clients[0].Register(ctx, "foo1", 60) + const registerTTL = 60 + recordTTL, err := clients[0].Register(ctx, "foo1", registerTTL) if err != nil { t.Fatal(err) } + if recordTTL != registerTTL*time.Second { + t.Fatalf("Expected record TTL to be %d seconds", DefaultTTL) + } rrs, cookie, err := clients[0].Discover(ctx, "foo1", 10, nil) if err != nil { @@ -92,10 +97,13 @@ func TestSVCRegistrationAndDiscovery(t *testing.T) { checkHostRegistration(t, rrs[0], hosts[1]) for i, client := range clients[1:] { - err = client.Register(ctx, "foo1", 60) + recordTTL, err = client.Register(ctx, "foo1", registerTTL) if err != nil { t.Fatal(err) } + if recordTTL != registerTTL*time.Second { + t.Fatalf("Expected record TTL to be %d seconds", DefaultTTL) + } rrs, cookie, err = clients[0].Discover(ctx, "foo1", 10, cookie) if err != nil { From 0e771cd3c2974bd7e6a2561aec395bd20d275e2b Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 21 Jun 2019 09:06:01 +0200 Subject: [PATCH 47/47] replaced sync.Map with map + RW mutex. small refactors --- discovery.go | 60 +++++++++++++++++++++++++++-------------------- discovery_test.go | 3 +-- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/discovery.go b/discovery.go index 94cac73..40e70e8 100644 --- a/discovery.go +++ b/discovery.go @@ -12,16 +12,17 @@ import ( ) type rendezvousDiscovery struct { - rp RendezvousPoint - peerCache sync.Map //is a map[string]discoveredPeerCache - rng *rand.Rand - rngMux sync.Mutex + rp RendezvousPoint + peerCache map[string]*discoveryCache + peerCacheMux sync.RWMutex + rng *rand.Rand + rngMux sync.Mutex } -type discoveredPeerCache struct { - cachedRecs map[peer.ID]*record - cookie []byte - mux sync.Mutex +type discoveryCache struct { + recs map[peer.ID]*record + cookie []byte + mux sync.Mutex } type record struct { @@ -31,7 +32,7 @@ type record struct { func NewRendezvousDiscovery(host host.Host, rendezvousPeer peer.ID) discovery.Discovery { rp := NewRendezvousPoint(host, rendezvousPeer) - return &rendezvousDiscovery{rp, sync.Map{}, rand.New(rand.NewSource(rand.Int63())), sync.Mutex{}} + return &rendezvousDiscovery{rp: rp, peerCache: make(map[string]*discoveryCache), rng: rand.New(rand.NewSource(rand.Int63()))} } func (c *rendezvousDiscovery) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) { @@ -51,10 +52,10 @@ func (c *rendezvousDiscovery) Advertise(ctx context.Context, ns string, opts ... ttlSeconds = int(math.Round(ttl.Seconds())) } - if returnedTTL, err := c.rp.Register(ctx, ns, ttlSeconds); err != nil { + if rttl, err := c.rp.Register(ctx, ns, ttlSeconds); err != nil { return 0, err } else { - return returnedTTL, nil + return rttl, nil } } @@ -73,23 +74,33 @@ func (c *rendezvousDiscovery) FindPeers(ctx context.Context, ns string, opts ... } // Get cached peers - var cache *discoveredPeerCache + var cache *discoveryCache - genericCache, _ := c.peerCache.LoadOrStore(ns, &discoveredPeerCache{}) - cache = genericCache.(*discoveredPeerCache) + c.peerCacheMux.RLock() + cache, ok := c.peerCache[ns] + c.peerCacheMux.RUnlock() + if !ok { + c.peerCacheMux.Lock() + cache, ok = c.peerCache[ns] + if !ok{ + cache = &discoveryCache{recs: make(map[peer.ID]*record)} + c.peerCache[ns] = cache + } + c.peerCacheMux.Unlock() + } cache.mux.Lock() defer cache.mux.Unlock() // Remove all expired entries from cache currentTime := time.Now().Unix() - newCacheSize := len(cache.cachedRecs) + newCacheSize := len(cache.recs) - for p := range cache.cachedRecs { - rec := cache.cachedRecs[p] + for p := range cache.recs { + rec := cache.recs[p] if rec.expire < currentTime { newCacheSize-- - delete(cache.cachedRecs, p) + delete(cache.recs, p) } } @@ -101,19 +112,16 @@ func (c *rendezvousDiscovery) FindPeers(ctx context.Context, ns string, opts ... var regs []Registration var newCookie []byte if regs, newCookie, err = c.rp.Discover(ctx, ns, limit, cookie); err == nil { - if cache.cachedRecs == nil { - cache.cachedRecs = make(map[peer.ID]*record) - } for _, reg := range regs { rec := &record{peer: reg.Peer, expire: int64(reg.Ttl) + currentTime} - cache.cachedRecs[rec.peer.ID] = rec + cache.recs[rec.peer.ID] = rec } cache.cookie = newCookie } } // Randomize and fill channel with available records - count := len(cache.cachedRecs) + count := len(cache.recs) if limit < count { count = limit } @@ -121,7 +129,7 @@ func (c *rendezvousDiscovery) FindPeers(ctx context.Context, ns string, opts ... chPeer := make(chan peer.AddrInfo, count) c.rngMux.Lock() - perm := c.rng.Perm(len(cache.cachedRecs))[0:count] + perm := c.rng.Perm(len(cache.recs))[0:count] c.rngMux.Unlock() permSet := make(map[int]int) @@ -131,9 +139,9 @@ func (c *rendezvousDiscovery) FindPeers(ctx context.Context, ns string, opts ... sendLst := make([]*peer.AddrInfo, count) iter := 0 - for k := range cache.cachedRecs { + for k := range cache.recs { if sendIndex, ok := permSet[iter]; ok { - sendLst[sendIndex] = &cache.cachedRecs[k].peer + sendLst[sendIndex] = &cache.recs[k].peer } iter++ } diff --git a/discovery_test.go b/discovery_test.go index 4091ef7..72161ce 100644 --- a/discovery_test.go +++ b/discovery_test.go @@ -6,7 +6,6 @@ import ( "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" "math/rand" - "sync" "testing" "time" ) @@ -17,7 +16,7 @@ func getRendezvousDiscovery(hosts []host.Host) []discovery.Discovery { for i, h := range hosts[1:] { rp := NewRendezvousPoint(h, rendezvousPeer) rng := rand.New(rand.NewSource(int64(i))) - clients[i] = &rendezvousDiscovery{rp: rp, peerCache: sync.Map{}, rng: rng} + clients[i] = &rendezvousDiscovery{rp: rp, peerCache: make(map[string]*discoveryCache), rng: rng} } return clients }