Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

11
vendor/github.com/libp2p/go-libp2p-kad-dht/pb/Makefile generated vendored Normal file
View File

@@ -0,0 +1,11 @@
PB = $(wildcard *.proto)
GO = $(PB:.proto=.pb.go)
all: $(GO)
%.pb.go: %.proto
protoc --proto_path=$(GOPATH)/src:. --gogofast_out=. $<
clean:
rm -f *.pb.go
rm -f *.go

View File

@@ -0,0 +1,42 @@
package dht_pb
import (
"encoding/json"
)
type byteString string
func (b byteString) Marshal() ([]byte, error) {
return []byte(b), nil
}
func (b *byteString) MarshalTo(data []byte) (int, error) {
return copy(data, *b), nil
}
func (b *byteString) Unmarshal(data []byte) error {
*b = byteString(data)
return nil
}
func (b *byteString) Size() int {
return len(*b)
}
func (b byteString) MarshalJSON() ([]byte, error) {
return json.Marshal([]byte(b))
}
func (b *byteString) UnmarshalJSON(data []byte) error {
var buf []byte
err := json.Unmarshal(data, &buf)
if err != nil {
return err
}
*b = byteString(buf)
return nil
}
func (b byteString) Equal(other byteString) bool {
return b == other
}

959
vendor/github.com/libp2p/go-libp2p-kad-dht/pb/dht.pb.go generated vendored Normal file
View File

@@ -0,0 +1,959 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: dht.proto
package dht_pb
import (
fmt "fmt"
io "io"
math "math"
math_bits "math/bits"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
pb "github.com/libp2p/go-libp2p-record/pb"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type Message_MessageType int32
const (
Message_PUT_VALUE Message_MessageType = 0
Message_GET_VALUE Message_MessageType = 1
Message_ADD_PROVIDER Message_MessageType = 2
Message_GET_PROVIDERS Message_MessageType = 3
Message_FIND_NODE Message_MessageType = 4
Message_PING Message_MessageType = 5
)
var Message_MessageType_name = map[int32]string{
0: "PUT_VALUE",
1: "GET_VALUE",
2: "ADD_PROVIDER",
3: "GET_PROVIDERS",
4: "FIND_NODE",
5: "PING",
}
var Message_MessageType_value = map[string]int32{
"PUT_VALUE": 0,
"GET_VALUE": 1,
"ADD_PROVIDER": 2,
"GET_PROVIDERS": 3,
"FIND_NODE": 4,
"PING": 5,
}
func (x Message_MessageType) String() string {
return proto.EnumName(Message_MessageType_name, int32(x))
}
func (Message_MessageType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_616a434b24c97ff4, []int{0, 0}
}
type Message_ConnectionType int32
const (
// sender does not have a connection to peer, and no extra information (default)
Message_NOT_CONNECTED Message_ConnectionType = 0
// sender has a live connection to peer
Message_CONNECTED Message_ConnectionType = 1
// sender recently connected to peer
Message_CAN_CONNECT Message_ConnectionType = 2
// sender recently tried to connect to peer repeatedly but failed to connect
// ("try" here is loose, but this should signal "made strong effort, failed")
Message_CANNOT_CONNECT Message_ConnectionType = 3
)
var Message_ConnectionType_name = map[int32]string{
0: "NOT_CONNECTED",
1: "CONNECTED",
2: "CAN_CONNECT",
3: "CANNOT_CONNECT",
}
var Message_ConnectionType_value = map[string]int32{
"NOT_CONNECTED": 0,
"CONNECTED": 1,
"CAN_CONNECT": 2,
"CANNOT_CONNECT": 3,
}
func (x Message_ConnectionType) String() string {
return proto.EnumName(Message_ConnectionType_name, int32(x))
}
func (Message_ConnectionType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_616a434b24c97ff4, []int{0, 1}
}
type Message struct {
// defines what type of message it is.
Type Message_MessageType `protobuf:"varint,1,opt,name=type,proto3,enum=dht.pb.Message_MessageType" json:"type,omitempty"`
// defines what coral cluster level this query/response belongs to.
// in case we want to implement coral's cluster rings in the future.
ClusterLevelRaw int32 `protobuf:"varint,10,opt,name=clusterLevelRaw,proto3" json:"clusterLevelRaw,omitempty"`
// Used to specify the key associated with this message.
// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
// Used to return a value
// PUT_VALUE, GET_VALUE
Record *pb.Record `protobuf:"bytes,3,opt,name=record,proto3" json:"record,omitempty"`
// Used to return peers closer to a key in a query
// GET_VALUE, GET_PROVIDERS, FIND_NODE
CloserPeers []Message_Peer `protobuf:"bytes,8,rep,name=closerPeers,proto3" json:"closerPeers"`
// Used to return Providers
// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
ProviderPeers []Message_Peer `protobuf:"bytes,9,rep,name=providerPeers,proto3" json:"providerPeers"`
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_616a434b24c97ff4, []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.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Message) XXX_Merge(src proto.Message) {
xxx_messageInfo_Message.Merge(m, 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 {
return m.Type
}
return Message_PUT_VALUE
}
func (m *Message) GetClusterLevelRaw() int32 {
if m != nil {
return m.ClusterLevelRaw
}
return 0
}
func (m *Message) GetKey() []byte {
if m != nil {
return m.Key
}
return nil
}
func (m *Message) GetRecord() *pb.Record {
if m != nil {
return m.Record
}
return nil
}
func (m *Message) GetCloserPeers() []Message_Peer {
if m != nil {
return m.CloserPeers
}
return nil
}
func (m *Message) GetProviderPeers() []Message_Peer {
if m != nil {
return m.ProviderPeers
}
return nil
}
type Message_Peer struct {
// ID of a given peer.
Id byteString `protobuf:"bytes,1,opt,name=id,proto3,customtype=byteString" json:"id"`
// multiaddrs for a given peer
Addrs [][]byte `protobuf:"bytes,2,rep,name=addrs,proto3" json:"addrs,omitempty"`
// used to signal the sender's connection capabilities to the peer
Connection Message_ConnectionType `protobuf:"varint,3,opt,name=connection,proto3,enum=dht.pb.Message_ConnectionType" json:"connection,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Message_Peer) Reset() { *m = Message_Peer{} }
func (m *Message_Peer) String() string { return proto.CompactTextString(m) }
func (*Message_Peer) ProtoMessage() {}
func (*Message_Peer) Descriptor() ([]byte, []int) {
return fileDescriptor_616a434b24c97ff4, []int{0, 0}
}
func (m *Message_Peer) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Message_Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Message_Peer.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Message_Peer) XXX_Merge(src proto.Message) {
xxx_messageInfo_Message_Peer.Merge(m, src)
}
func (m *Message_Peer) XXX_Size() int {
return m.Size()
}
func (m *Message_Peer) XXX_DiscardUnknown() {
xxx_messageInfo_Message_Peer.DiscardUnknown(m)
}
var xxx_messageInfo_Message_Peer proto.InternalMessageInfo
func (m *Message_Peer) GetAddrs() [][]byte {
if m != nil {
return m.Addrs
}
return nil
}
func (m *Message_Peer) GetConnection() Message_ConnectionType {
if m != nil {
return m.Connection
}
return Message_NOT_CONNECTED
}
func init() {
proto.RegisterEnum("dht.pb.Message_MessageType", Message_MessageType_name, Message_MessageType_value)
proto.RegisterEnum("dht.pb.Message_ConnectionType", Message_ConnectionType_name, Message_ConnectionType_value)
proto.RegisterType((*Message)(nil), "dht.pb.Message")
proto.RegisterType((*Message_Peer)(nil), "dht.pb.Message.Peer")
}
func init() { proto.RegisterFile("dht.proto", fileDescriptor_616a434b24c97ff4) }
var fileDescriptor_616a434b24c97ff4 = []byte{
// 469 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xb1, 0x6f, 0x9b, 0x40,
0x18, 0xc5, 0x73, 0x80, 0xdd, 0xf8, 0x03, 0x3b, 0xe4, 0x94, 0x01, 0xb9, 0x92, 0x83, 0x3c, 0xd1,
0xc1, 0x20, 0xd1, 0xb5, 0xaa, 0x6a, 0x03, 0x8d, 0x2c, 0xa5, 0xd8, 0xba, 0x38, 0xe9, 0x68, 0x19,
0xb8, 0x12, 0x54, 0xd7, 0x87, 0x00, 0xa7, 0xf2, 0xd6, 0x3f, 0x2f, 0x63, 0xe7, 0x0e, 0x51, 0xe5,
0xa9, 0x7f, 0x46, 0xc5, 0x11, 0x5a, 0xec, 0x25, 0x13, 0xef, 0x7d, 0xf7, 0x7e, 0xe2, 0xdd, 0xa7,
0x83, 0x4e, 0x74, 0x5f, 0x98, 0x69, 0xc6, 0x0a, 0x86, 0xdb, 0x5c, 0x06, 0x7d, 0x3b, 0x4e, 0x8a,
0xfb, 0x6d, 0x60, 0x86, 0xec, 0x9b, 0xb5, 0x4e, 0x82, 0xd4, 0x4e, 0xad, 0x98, 0x8d, 0x2a, 0x35,
0xca, 0x68, 0xc8, 0xb2, 0xc8, 0x4a, 0x03, 0xab, 0x52, 0x15, 0xdb, 0x1f, 0x35, 0x98, 0x98, 0xc5,
0xcc, 0xe2, 0xe3, 0x60, 0xfb, 0x85, 0x3b, 0x6e, 0xb8, 0xaa, 0xe2, 0xc3, 0x3f, 0x12, 0xbc, 0xfa,
0x44, 0xf3, 0x7c, 0x15, 0x53, 0x6c, 0x81, 0x54, 0xec, 0x52, 0xaa, 0x21, 0x1d, 0x19, 0x3d, 0xfb,
0xb5, 0x59, 0xb5, 0x30, 0x9f, 0x8f, 0xeb, 0xef, 0x62, 0x97, 0x52, 0xc2, 0x83, 0xd8, 0x80, 0xb3,
0x70, 0xbd, 0xcd, 0x0b, 0x9a, 0x5d, 0xd3, 0x07, 0xba, 0x26, 0xab, 0xef, 0x1a, 0xe8, 0xc8, 0x68,
0x91, 0xe3, 0x31, 0x56, 0x41, 0xfc, 0x4a, 0x77, 0x9a, 0xa0, 0x23, 0x43, 0x21, 0xa5, 0xc4, 0x6f,
0xa0, 0x5d, 0xf5, 0xd6, 0x44, 0x1d, 0x19, 0xb2, 0x7d, 0x6e, 0xd6, 0xd7, 0x08, 0x4c, 0xc2, 0x15,
0x79, 0x0e, 0xe0, 0x77, 0x20, 0x87, 0x6b, 0x96, 0xd3, 0x6c, 0x4e, 0x69, 0x96, 0x6b, 0xa7, 0xba,
0x68, 0xc8, 0xf6, 0xc5, 0x71, 0xbd, 0xf2, 0x70, 0x22, 0x3d, 0x3e, 0x5d, 0x9e, 0x90, 0x66, 0x1c,
0x7f, 0x80, 0x6e, 0x9a, 0xb1, 0x87, 0x24, 0xaa, 0xf9, 0xce, 0x8b, 0xfc, 0x21, 0xd0, 0xff, 0x81,
0x40, 0x2a, 0x15, 0x1e, 0x82, 0x90, 0x44, 0x7c, 0x3d, 0xca, 0x04, 0x97, 0xc9, 0x5f, 0x4f, 0x97,
0x10, 0xec, 0x0a, 0x7a, 0x53, 0x64, 0xc9, 0x26, 0x26, 0x42, 0x12, 0xe1, 0x0b, 0x68, 0xad, 0xa2,
0x28, 0xcb, 0x35, 0x41, 0x17, 0x0d, 0x85, 0x54, 0x06, 0xbf, 0x07, 0x08, 0xd9, 0x66, 0x43, 0xc3,
0x22, 0x61, 0x1b, 0x7e, 0xe3, 0x9e, 0x3d, 0x38, 0x6e, 0xe0, 0xfc, 0x4b, 0xf0, 0x1d, 0x37, 0x88,
0x61, 0x02, 0x72, 0x63, 0xfd, 0xb8, 0x0b, 0x9d, 0xf9, 0xed, 0x62, 0x79, 0x37, 0xbe, 0xbe, 0xf5,
0xd4, 0x93, 0xd2, 0x5e, 0x79, 0xb5, 0x45, 0x58, 0x05, 0x65, 0xec, 0xba, 0xcb, 0x39, 0x99, 0xdd,
0x4d, 0x5d, 0x8f, 0xa8, 0x02, 0x3e, 0x87, 0x6e, 0x19, 0xa8, 0x27, 0x37, 0xaa, 0x58, 0x32, 0x1f,
0xa7, 0xbe, 0xbb, 0xf4, 0x67, 0xae, 0xa7, 0x4a, 0xf8, 0x14, 0xa4, 0xf9, 0xd4, 0xbf, 0x52, 0x5b,
0xc3, 0xcf, 0xd0, 0x3b, 0x2c, 0x52, 0xd2, 0xfe, 0x6c, 0xb1, 0x74, 0x66, 0xbe, 0xef, 0x39, 0x0b,
0xcf, 0xad, 0xfe, 0xf8, 0xdf, 0x22, 0x7c, 0x06, 0xb2, 0x33, 0xf6, 0xeb, 0x84, 0x2a, 0x60, 0x0c,
0x3d, 0x67, 0xec, 0x37, 0x28, 0x55, 0x9c, 0x28, 0x8f, 0xfb, 0x01, 0xfa, 0xb9, 0x1f, 0xa0, 0xdf,
0xfb, 0x01, 0x0a, 0xda, 0xfc, 0xfd, 0xbd, 0xfd, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x8d, 0x1a, 0xa1,
0xbe, 0xf7, 0x02, 0x00, 0x00,
}
func (m *Message) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Message) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Message) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.ClusterLevelRaw != 0 {
i = encodeVarintDht(dAtA, i, uint64(m.ClusterLevelRaw))
i--
dAtA[i] = 0x50
}
if len(m.ProviderPeers) > 0 {
for iNdEx := len(m.ProviderPeers) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.ProviderPeers[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintDht(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x4a
}
}
if len(m.CloserPeers) > 0 {
for iNdEx := len(m.CloserPeers) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.CloserPeers[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintDht(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x42
}
}
if m.Record != nil {
{
size, err := m.Record.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintDht(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
}
if len(m.Key) > 0 {
i -= len(m.Key)
copy(dAtA[i:], m.Key)
i = encodeVarintDht(dAtA, i, uint64(len(m.Key)))
i--
dAtA[i] = 0x12
}
if m.Type != 0 {
i = encodeVarintDht(dAtA, i, uint64(m.Type))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *Message_Peer) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Message_Peer) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Message_Peer) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.XXX_unrecognized != nil {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.Connection != 0 {
i = encodeVarintDht(dAtA, i, uint64(m.Connection))
i--
dAtA[i] = 0x18
}
if len(m.Addrs) > 0 {
for iNdEx := len(m.Addrs) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Addrs[iNdEx])
copy(dAtA[i:], m.Addrs[iNdEx])
i = encodeVarintDht(dAtA, i, uint64(len(m.Addrs[iNdEx])))
i--
dAtA[i] = 0x12
}
}
{
size := m.Id.Size()
i -= size
if _, err := m.Id.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintDht(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func encodeVarintDht(dAtA []byte, offset int, v uint64) int {
offset -= sovDht(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *Message) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Type != 0 {
n += 1 + sovDht(uint64(m.Type))
}
l = len(m.Key)
if l > 0 {
n += 1 + l + sovDht(uint64(l))
}
if m.Record != nil {
l = m.Record.Size()
n += 1 + l + sovDht(uint64(l))
}
if len(m.CloserPeers) > 0 {
for _, e := range m.CloserPeers {
l = e.Size()
n += 1 + l + sovDht(uint64(l))
}
}
if len(m.ProviderPeers) > 0 {
for _, e := range m.ProviderPeers {
l = e.Size()
n += 1 + l + sovDht(uint64(l))
}
}
if m.ClusterLevelRaw != 0 {
n += 1 + sovDht(uint64(m.ClusterLevelRaw))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *Message_Peer) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = m.Id.Size()
n += 1 + l + sovDht(uint64(l))
if len(m.Addrs) > 0 {
for _, b := range m.Addrs {
l = len(b)
n += 1 + l + sovDht(uint64(l))
}
}
if m.Connection != 0 {
n += 1 + sovDht(uint64(m.Connection))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func sovDht(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozDht(x uint64) (n int) {
return sovDht(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 ErrIntOverflowDht
}
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)
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Type |= Message_MessageType(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthDht
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...)
if m.Key == nil {
m.Key = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Record", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthDht
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Record == nil {
m.Record = &pb.Record{}
}
if err := m.Record.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CloserPeers", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthDht
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CloserPeers = append(m.CloserPeers, Message_Peer{})
if err := m.CloserPeers[len(m.CloserPeers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ProviderPeers", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthDht
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ProviderPeers = append(m.ProviderPeers, Message_Peer{})
if err := m.ProviderPeers[len(m.ProviderPeers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 10:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ClusterLevelRaw", wireType)
}
m.ClusterLevelRaw = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ClusterLevelRaw |= int32(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipDht(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDht
}
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_Peer) 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 ErrIntOverflowDht
}
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: Peer: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Peer: 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 ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthDht
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Id.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
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 ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthDht
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthDht
}
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
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Connection", wireType)
}
m.Connection = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowDht
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Connection |= Message_ConnectionType(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipDht(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDht
}
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 skipDht(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowDht
}
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, ErrIntOverflowDht
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowDht
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthDht
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupDht
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthDht
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthDht = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowDht = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupDht = fmt.Errorf("proto: unexpected end of group")
)

View File

@@ -0,0 +1,72 @@
// In order to re-generate the golang packages for `Message` you will need...
// 1. Protobuf binary (tested with protoc 3.0.0). - https://github.com/gogo/protobuf/releases
// 2. Gogo Protobuf (tested with gogo 0.3). - https://github.com/gogo/protobuf
// 3. To have cloned `libp2p/go-libp2p-{record,kad-dht}` under the same directory.
// Now from `libp2p/go-libp2p-kad-dht/pb` you can run...
// `protoc --gogo_out=. --proto_path=../../go-libp2p-record/pb/ --proto_path=./ dht.proto`
syntax = "proto3";
package dht.pb;
import "github.com/libp2p/go-libp2p-record/pb/record.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
message Message {
enum MessageType {
PUT_VALUE = 0;
GET_VALUE = 1;
ADD_PROVIDER = 2;
GET_PROVIDERS = 3;
FIND_NODE = 4;
PING = 5;
}
enum ConnectionType {
// sender does not have a connection to peer, and no extra information (default)
NOT_CONNECTED = 0;
// sender has a live connection to peer
CONNECTED = 1;
// sender recently connected to peer
CAN_CONNECT = 2;
// sender recently tried to connect to peer repeatedly but failed to connect
// ("try" here is loose, but this should signal "made strong effort, failed")
CANNOT_CONNECT = 3;
}
message Peer {
// ID of a given peer.
bytes id = 1 [(gogoproto.customtype) = "byteString", (gogoproto.nullable) = false];
// multiaddrs for a given peer
repeated bytes addrs = 2;
// used to signal the sender's connection capabilities to the peer
ConnectionType connection = 3;
}
// defines what type of message it is.
MessageType type = 1;
// defines what coral cluster level this query/response belongs to.
// in case we want to implement coral's cluster rings in the future.
int32 clusterLevelRaw = 10;
// Used to specify the key associated with this message.
// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
bytes key = 2;
// Used to return a value
// PUT_VALUE, GET_VALUE
record.pb.Record record = 3;
// Used to return peers closer to a key in a query
// GET_VALUE, GET_PROVIDERS, FIND_NODE
repeated Peer closerPeers = 8 [(gogoproto.nullable) = false];
// Used to return Providers
// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
repeated Peer providerPeers = 9 [(gogoproto.nullable) = false];
}

View File

@@ -0,0 +1,171 @@
package dht_pb
import (
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
logging "github.com/ipfs/go-log"
ma "github.com/multiformats/go-multiaddr"
)
var log = logging.Logger("dht.pb")
type PeerRoutingInfo struct {
peer.AddrInfo
network.Connectedness
}
// NewMessage constructs a new dht message with given type, key, and level
func NewMessage(typ Message_MessageType, key []byte, level int) *Message {
m := &Message{
Type: typ,
Key: key,
}
m.SetClusterLevel(level)
return m
}
func peerRoutingInfoToPBPeer(p PeerRoutingInfo) Message_Peer {
var pbp Message_Peer
pbp.Addrs = make([][]byte, len(p.Addrs))
for i, maddr := range p.Addrs {
pbp.Addrs[i] = maddr.Bytes() // Bytes, not String. Compressed.
}
pbp.Id = byteString(p.ID)
pbp.Connection = ConnectionType(p.Connectedness)
return pbp
}
func peerInfoToPBPeer(p peer.AddrInfo) Message_Peer {
var pbp Message_Peer
pbp.Addrs = make([][]byte, len(p.Addrs))
for i, maddr := range p.Addrs {
pbp.Addrs[i] = maddr.Bytes() // Bytes, not String. Compressed.
}
pbp.Id = byteString(p.ID)
return pbp
}
// PBPeerToPeer turns a *Message_Peer into its peer.AddrInfo counterpart
func PBPeerToPeerInfo(pbp Message_Peer) peer.AddrInfo {
return peer.AddrInfo{
ID: peer.ID(pbp.Id),
Addrs: pbp.Addresses(),
}
}
// RawPeerInfosToPBPeers converts a slice of Peers into a slice of *Message_Peers,
// ready to go out on the wire.
func RawPeerInfosToPBPeers(peers []peer.AddrInfo) []Message_Peer {
pbpeers := make([]Message_Peer, len(peers))
for i, p := range peers {
pbpeers[i] = peerInfoToPBPeer(p)
}
return pbpeers
}
// PeersToPBPeers converts given []peer.Peer into a set of []*Message_Peer,
// which can be written to a message and sent out. the key thing this function
// does (in addition to PeersToPBPeers) is set the ConnectionType with
// information from the given network.Network.
func PeerInfosToPBPeers(n network.Network, peers []peer.AddrInfo) []Message_Peer {
pbps := RawPeerInfosToPBPeers(peers)
for i, pbp := range pbps {
c := ConnectionType(n.Connectedness(peers[i].ID))
pbp.Connection = c
}
return pbps
}
func PeerRoutingInfosToPBPeers(peers []PeerRoutingInfo) []Message_Peer {
pbpeers := make([]Message_Peer, len(peers))
for i, p := range peers {
pbpeers[i] = peerRoutingInfoToPBPeer(p)
}
return pbpeers
}
// PBPeersToPeerInfos converts given []*Message_Peer into []peer.AddrInfo
// Invalid addresses will be silently omitted.
func PBPeersToPeerInfos(pbps []Message_Peer) []*peer.AddrInfo {
peers := make([]*peer.AddrInfo, 0, len(pbps))
for _, pbp := range pbps {
ai := PBPeerToPeerInfo(pbp)
peers = append(peers, &ai)
}
return peers
}
// Addresses returns a multiaddr associated with the Message_Peer entry
func (m *Message_Peer) Addresses() []ma.Multiaddr {
if m == nil {
return nil
}
maddrs := make([]ma.Multiaddr, 0, len(m.Addrs))
for _, addr := range m.Addrs {
maddr, err := ma.NewMultiaddrBytes(addr)
if err != nil {
log.Debugw("error decoding multiaddr for peer", "peer", peer.ID(m.Id), "error", err)
continue
}
maddrs = append(maddrs, maddr)
}
return maddrs
}
// GetClusterLevel gets and adjusts the cluster level on the message.
// a +/- 1 adjustment is needed to distinguish a valid first level (1) and
// default "no value" protobuf behavior (0)
func (m *Message) GetClusterLevel() int {
level := m.GetClusterLevelRaw() - 1
if level < 0 {
return 0
}
return int(level)
}
// SetClusterLevel adjusts and sets the cluster level on the message.
// a +/- 1 adjustment is needed to distinguish a valid first level (1) and
// default "no value" protobuf behavior (0)
func (m *Message) SetClusterLevel(level int) {
lvl := int32(level)
m.ClusterLevelRaw = lvl + 1
}
// ConnectionType returns a Message_ConnectionType associated with the
// network.Connectedness.
func ConnectionType(c network.Connectedness) Message_ConnectionType {
switch c {
default:
return Message_NOT_CONNECTED
case network.NotConnected:
return Message_NOT_CONNECTED
case network.Connected:
return Message_CONNECTED
case network.CanConnect:
return Message_CAN_CONNECT
case network.CannotConnect:
return Message_CANNOT_CONNECT
}
}
// Connectedness returns an network.Connectedness associated with the
// Message_ConnectionType.
func Connectedness(c Message_ConnectionType) network.Connectedness {
switch c {
default:
return network.NotConnected
case Message_NOT_CONNECTED:
return network.NotConnected
case Message_CONNECTED:
return network.Connected
case Message_CAN_CONNECT:
return network.CanConnect
case Message_CANNOT_CONNECT:
return network.CannotConnect
}
}

View File

@@ -0,0 +1,261 @@
package dht_pb
import (
"bytes"
"context"
"errors"
"fmt"
logging "github.com/ipfs/go-log"
recpb "github.com/libp2p/go-libp2p-record/pb"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multihash"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"github.com/libp2p/go-libp2p-kad-dht/internal"
)
var logger = logging.Logger("dht")
// ProtocolMessenger can be used for sending DHT messages to peers and processing their responses.
// This decouples the wire protocol format from both the DHT protocol implementation and from the implementation of the
// routing.Routing interface.
//
// Note: the ProtocolMessenger's MessageSender still needs to deal with some wire protocol details such as using
// varint-delineated protobufs
type ProtocolMessenger struct {
m MessageSender
}
type ProtocolMessengerOption func(*ProtocolMessenger) error
// NewProtocolMessenger creates a new ProtocolMessenger that is used for sending DHT messages to peers and processing
// their responses.
func NewProtocolMessenger(msgSender MessageSender, opts ...ProtocolMessengerOption) (*ProtocolMessenger, error) {
pm := &ProtocolMessenger{
m: msgSender,
}
for _, o := range opts {
if err := o(pm); err != nil {
return nil, err
}
}
return pm, nil
}
type MessageSenderWithDisconnect interface {
MessageSender
OnDisconnect(context.Context, peer.ID)
}
// MessageSender handles sending wire protocol messages to a given peer
type MessageSender interface {
// SendRequest sends a peer a message and waits for its response
SendRequest(ctx context.Context, p peer.ID, pmes *Message) (*Message, error)
// SendMessage sends a peer a message without waiting on a response
SendMessage(ctx context.Context, p peer.ID, pmes *Message) error
}
// PutValue asks a peer to store the given key/value pair.
func (pm *ProtocolMessenger) PutValue(ctx context.Context, p peer.ID, rec *recpb.Record) (err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.PutValue")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p), attribute.Stringer("record", rec))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
}
}()
}
pmes := NewMessage(Message_PUT_VALUE, rec.Key, 0)
pmes.Record = rec
rpmes, err := pm.m.SendRequest(ctx, p, pmes)
if err != nil {
logger.Debugw("failed to put value to peer", "to", p, "key", internal.LoggableRecordKeyBytes(rec.Key), "error", err)
return err
}
if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
const errStr = "value not put correctly"
logger.Infow(errStr, "put-message", pmes, "get-message", rpmes)
return errors.New(errStr)
}
return nil
}
// GetValue asks a peer for the value corresponding to the given key. Also returns the K closest peers to the key
// as described in GetClosestPeers.
func (pm *ProtocolMessenger) GetValue(ctx context.Context, p peer.ID, key string) (record *recpb.Record, closerPeers []*peer.AddrInfo, err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.GetValue")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p), internal.KeyAsAttribute("key", key))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
} else {
peers := make([]string, len(closerPeers))
for i, v := range closerPeers {
peers[i] = v.String()
}
span.SetAttributes(
attribute.Stringer("record", record),
attribute.StringSlice("closestPeers", peers),
)
}
}()
}
pmes := NewMessage(Message_GET_VALUE, []byte(key), 0)
respMsg, err := pm.m.SendRequest(ctx, p, pmes)
if err != nil {
return nil, nil, err
}
// Perhaps we were given closer peers
peers := PBPeersToPeerInfos(respMsg.GetCloserPeers())
if rec := respMsg.GetRecord(); rec != nil {
// Success! We were given the value
logger.Debug("got value")
// Check that record matches the one we are looking for (validation of the record does not happen here)
if !bytes.Equal([]byte(key), rec.GetKey()) {
logger.Debug("received incorrect record")
return nil, nil, internal.ErrIncorrectRecord
}
return rec, peers, err
}
return nil, peers, nil
}
// GetClosestPeers asks a peer to return the K (a DHT-wide parameter) DHT server peers closest in XOR space to the id
// Note: If the peer happens to know another peer whose peerID exactly matches the given id it will return that peer
// even if that peer is not a DHT server node.
func (pm *ProtocolMessenger) GetClosestPeers(ctx context.Context, p peer.ID, id peer.ID) (closerPeers []*peer.AddrInfo, err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.GetClosestPeers")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p), attribute.Stringer("key", id))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
} else {
peers := make([]string, len(closerPeers))
for i, v := range closerPeers {
peers[i] = v.String()
}
span.SetAttributes(attribute.StringSlice("peers", peers))
}
}()
}
pmes := NewMessage(Message_FIND_NODE, []byte(id), 0)
respMsg, err := pm.m.SendRequest(ctx, p, pmes)
if err != nil {
return nil, err
}
peers := PBPeersToPeerInfos(respMsg.GetCloserPeers())
return peers, nil
}
// PutProvider is deprecated please use [ProtocolMessenger.PutProviderAddrs].
func (pm *ProtocolMessenger) PutProvider(ctx context.Context, p peer.ID, key multihash.Multihash, h host.Host) error {
return pm.PutProviderAddrs(ctx, p, key, peer.AddrInfo{
ID: h.ID(),
Addrs: h.Addrs(),
})
}
// PutProviderAddrs asks a peer to store that we are a provider for the given key.
func (pm *ProtocolMessenger) PutProviderAddrs(ctx context.Context, p peer.ID, key multihash.Multihash, self peer.AddrInfo) (err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.PutProvider")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p), attribute.Stringer("key", key))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
}
}()
}
// TODO: We may want to limit the type of addresses in our provider records
// For example, in a WAN-only DHT prohibit sharing non-WAN addresses (e.g. 192.168.0.100)
if len(self.Addrs) < 1 {
return fmt.Errorf("no known addresses for self, cannot put provider")
}
pmes := NewMessage(Message_ADD_PROVIDER, key, 0)
pmes.ProviderPeers = RawPeerInfosToPBPeers([]peer.AddrInfo{self})
return pm.m.SendMessage(ctx, p, pmes)
}
// GetProviders asks a peer for the providers it knows of for a given key. Also returns the K closest peers to the key
// as described in GetClosestPeers.
func (pm *ProtocolMessenger) GetProviders(ctx context.Context, p peer.ID, key multihash.Multihash) (provs []*peer.AddrInfo, closerPeers []*peer.AddrInfo, err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.GetProviders")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p), attribute.Stringer("key", key))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
} else {
provsStr := make([]string, len(provs))
for i, v := range provs {
provsStr[i] = v.String()
}
closerPeersStr := make([]string, len(provs))
for i, v := range provs {
closerPeersStr[i] = v.String()
}
span.SetAttributes(attribute.StringSlice("provs", provsStr), attribute.StringSlice("closestPeers", closerPeersStr))
}
}()
}
pmes := NewMessage(Message_GET_PROVIDERS, key, 0)
respMsg, err := pm.m.SendRequest(ctx, p, pmes)
if err != nil {
return nil, nil, err
}
provs = PBPeersToPeerInfos(respMsg.GetProviderPeers())
closerPeers = PBPeersToPeerInfos(respMsg.GetCloserPeers())
return provs, closerPeers, nil
}
// Ping sends a ping message to the passed peer and waits for a response.
func (pm *ProtocolMessenger) Ping(ctx context.Context, p peer.ID) (err error) {
ctx, span := internal.StartSpan(ctx, "ProtocolMessenger.Ping")
defer span.End()
if span.IsRecording() {
span.SetAttributes(attribute.Stringer("to", p))
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
}
}()
}
req := NewMessage(Message_PING, nil, 0)
resp, err := pm.m.SendRequest(ctx, p, req)
if err != nil {
return fmt.Errorf("sending request: %w", err)
}
if resp.Type != Message_PING {
return fmt.Errorf("got unexpected response type: %v", resp.Type)
}
return nil
}