lbry.go/dht/message.go

287 lines
6.1 KiB
Go
Raw Normal View History

2018-03-07 22:15:58 +01:00
package dht
import (
"encoding/hex"
2018-04-03 18:14:04 +02:00
"strings"
2018-03-07 22:15:58 +01:00
"github.com/lbryio/errors.go"
"github.com/lyoshenka/bencode"
2018-03-07 22:15:58 +01:00
"github.com/spf13/cast"
)
const (
pingMethod = "ping"
storeMethod = "store"
findNodeMethod = "findNode"
findValueMethod = "findValue"
)
const (
pingSuccessResponse = "pong"
storeSuccessResponse = "OK"
)
const (
requestType = 0
responseType = 1
errorType = 2
)
const (
// these are strings because bencode requires bytestring keys
headerTypeField = "0"
headerMessageIDField = "1" // message id is 20 bytes long
headerNodeIDField = "2" // node id is 48 bytes long
headerPayloadField = "3"
headerArgsField = "4"
)
type Message interface {
bencode.Marshaler
}
type Request struct {
ID string
NodeID string
Method string
Args []string
StoreArgs *storeArgs
}
func (r Request) MarshalBencode() ([]byte, error) {
var args interface{}
if r.StoreArgs != nil {
args = r.StoreArgs
} else {
args = r.Args
}
return bencode.EncodeBytes(map[string]interface{}{
headerTypeField: requestType,
headerMessageIDField: r.ID,
headerNodeIDField: r.NodeID,
headerPayloadField: r.Method,
headerArgsField: args,
})
}
func (r *Request) UnmarshalBencode(b []byte) error {
var raw struct {
ID string `bencode:"1"`
NodeID string `bencode:"2"`
Method string `bencode:"3"`
Args bencode.RawMessage `bencode:"4"`
}
err := bencode.DecodeBytes(b, &raw)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("request unmarshal", err)
2018-03-07 22:15:58 +01:00
}
r.ID = raw.ID
r.NodeID = raw.NodeID
r.Method = raw.Method
if r.Method == storeMethod {
2018-03-08 01:49:33 +01:00
r.StoreArgs = &storeArgs{} // bencode wont find the unmarshaler on a null pointer. need to fix it.
2018-03-07 22:15:58 +01:00
err = bencode.DecodeBytes(raw.Args, &r.StoreArgs)
} else {
err = bencode.DecodeBytes(raw.Args, &r.Args)
}
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("request unmarshal", err)
2018-03-07 22:15:58 +01:00
}
return nil
}
type storeArgs struct {
2018-03-08 01:49:33 +01:00
BlobHash string
2018-03-07 22:15:58 +01:00
Value struct {
Token string `bencode:"token"`
LbryID string `bencode:"lbryid"`
Port int `bencode:"port"`
}
2018-03-08 01:49:33 +01:00
NodeID bitmap
SelfStore bool // this is an int on the wire
2018-03-07 22:15:58 +01:00
}
2018-03-08 01:49:33 +01:00
func (s storeArgs) MarshalBencode() ([]byte, error) {
2018-03-07 22:15:58 +01:00
encodedValue, err := bencode.EncodeString(s.Value)
if err != nil {
return nil, err
}
selfStoreStr := 0
if s.SelfStore {
selfStoreStr = 1
}
return bencode.EncodeBytes([]interface{}{
s.BlobHash,
bencode.RawMessage(encodedValue),
s.NodeID,
selfStoreStr,
})
}
func (s *storeArgs) UnmarshalBencode(b []byte) error {
var argsInt []bencode.RawMessage
err := bencode.DecodeBytes(b, &argsInt)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("storeArgs unmarshal", err)
2018-03-07 22:15:58 +01:00
}
if len(argsInt) != 4 {
return errors.Err("unexpected number of fields for store args. got " + cast.ToString(len(argsInt)))
}
err = bencode.DecodeBytes(argsInt[0], &s.BlobHash)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("storeArgs unmarshal", err)
2018-03-07 22:15:58 +01:00
}
err = bencode.DecodeBytes(argsInt[1], &s.Value)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("storeArgs unmarshal", err)
2018-03-07 22:15:58 +01:00
}
err = bencode.DecodeBytes(argsInt[2], &s.NodeID)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("storeArgs unmarshal", err)
2018-03-07 22:15:58 +01:00
}
var selfStore int
err = bencode.DecodeBytes(argsInt[3], &selfStore)
if err != nil {
2018-03-08 01:49:33 +01:00
return errors.Prefix("storeArgs unmarshal", err)
2018-03-07 22:15:58 +01:00
}
if selfStore == 0 {
s.SelfStore = false
} else if selfStore == 1 {
s.SelfStore = true
} else {
return errors.Err("selfstore must be 1 or 0")
}
return nil
}
type Response struct {
ID string
NodeID string
Data string
FindNodeData []Node
FindValueKey string
2018-03-07 22:15:58 +01:00
}
func (r Response) ArgsDebug() string {
2018-04-03 18:14:04 +02:00
if r.Data != "" {
return r.Data
}
str := "contacts "
if r.FindValueKey != "" {
2018-04-03 18:14:04 +02:00
str = "value for " + hex.EncodeToString([]byte(r.FindValueKey))[:8] + " "
}
2018-04-03 18:14:04 +02:00
str += "|"
for _, c := range r.FindNodeData {
2018-04-03 18:14:04 +02:00
str += c.Addr().String() + ":" + c.id.HexShort() + ","
}
2018-04-03 18:14:04 +02:00
str = strings.TrimRight(str, ",") + "|"
return str
}
2018-03-07 22:15:58 +01:00
func (r Response) MarshalBencode() ([]byte, error) {
data := map[string]interface{}{
headerTypeField: responseType,
headerMessageIDField: r.ID,
headerNodeIDField: r.NodeID,
}
if r.Data != "" {
data[headerPayloadField] = r.Data
2018-03-09 22:43:30 +01:00
} else if r.FindValueKey != "" {
var contacts [][]byte
for _, n := range r.FindNodeData {
compact, err := n.MarshalCompact()
if err != nil {
return nil, err
}
contacts = append(contacts, compact)
}
data[headerPayloadField] = map[string][][]byte{r.FindValueKey: contacts}
2018-03-07 22:15:58 +01:00
} else {
2018-03-09 22:43:30 +01:00
data[headerPayloadField] = map[string][]Node{"contacts": r.FindNodeData}
2018-03-07 22:15:58 +01:00
}
return bencode.EncodeBytes(data)
}
func (r *Response) UnmarshalBencode(b []byte) error {
var raw struct {
ID string `bencode:"1"`
NodeID string `bencode:"2"`
Data bencode.RawMessage `bencode:"3"`
2018-03-07 22:15:58 +01:00
}
err := bencode.DecodeBytes(b, &raw)
if err != nil {
return err
}
r.ID = raw.ID
r.NodeID = raw.NodeID
err = bencode.DecodeBytes(raw.Data, &r.Data)
if err != nil {
2018-03-29 03:05:27 +02:00
var rawData map[string]bencode.RawMessage
err = bencode.DecodeBytes(raw.Data, &rawData)
if err != nil {
return err
}
2018-04-03 18:14:04 +02:00
if contacts, ok := rawData["contacts"]; ok {
err = bencode.DecodeBytes(contacts, &r.FindNodeData)
if err != nil {
return err
}
} else {
2018-03-29 03:05:27 +02:00
for k, v := range rawData {
r.FindValueKey = k
2018-04-03 18:14:04 +02:00
var compactNodes [][]byte
err = bencode.DecodeBytes(v, &compactNodes)
if err != nil {
return err
}
for _, compact := range compactNodes {
var uncompactedNode Node
err = uncompactedNode.UnmarshalCompact(compact)
if err != nil {
return err
}
r.FindNodeData = append(r.FindNodeData, uncompactedNode)
}
2018-03-29 03:05:27 +02:00
break
}
}
2018-03-07 22:15:58 +01:00
}
2018-03-08 01:49:33 +01:00
return nil
2018-03-07 22:15:58 +01:00
}
type Error struct {
ID string
NodeID string
Response []string
ExceptionType string
}
func (e Error) MarshalBencode() ([]byte, error) {
return bencode.EncodeBytes(map[string]interface{}{
headerTypeField: errorType,
headerMessageIDField: e.ID,
headerNodeIDField: e.NodeID,
headerPayloadField: e.ExceptionType,
headerArgsField: e.Response,
})
}