103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
package dht
|
|
|
|
import "github.com/zeebo/bencode"
|
|
|
|
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"
|
|
headerNodeIDField = "2"
|
|
headerPayloadField = "3"
|
|
headerArgsField = "4"
|
|
)
|
|
|
|
type Message interface {
|
|
GetID() string
|
|
Encode() ([]byte, error)
|
|
}
|
|
|
|
type Request struct {
|
|
ID string
|
|
NodeID string
|
|
Method string
|
|
Args []string
|
|
}
|
|
|
|
func (r Request) GetID() string { return r.ID }
|
|
func (r Request) Encode() ([]byte, error) {
|
|
return bencode.EncodeBytes(map[string]interface{}{
|
|
headerTypeField: requestType,
|
|
headerMessageIDField: r.ID,
|
|
headerNodeIDField: r.NodeID,
|
|
headerPayloadField: r.Method,
|
|
headerArgsField: r.Args,
|
|
})
|
|
}
|
|
|
|
type findNodeDatum struct {
|
|
ID string
|
|
IP string
|
|
Port int
|
|
}
|
|
type Response struct {
|
|
ID string
|
|
NodeID string
|
|
Data string
|
|
FindNodeData []findNodeDatum
|
|
}
|
|
|
|
func (r Response) GetID() string { return r.ID }
|
|
func (r Response) Encode() ([]byte, error) {
|
|
data := map[string]interface{}{
|
|
headerTypeField: responseType,
|
|
headerMessageIDField: r.ID,
|
|
headerNodeIDField: r.NodeID,
|
|
}
|
|
if r.Data != "" {
|
|
data[headerPayloadField] = r.Data
|
|
} else {
|
|
var nodes []interface{}
|
|
for _, n := range r.FindNodeData {
|
|
nodes = append(nodes, []interface{}{n.ID, n.IP, n.Port})
|
|
}
|
|
data[headerPayloadField] = nodes
|
|
}
|
|
|
|
return bencode.EncodeBytes(data)
|
|
}
|
|
|
|
type Error struct {
|
|
ID string
|
|
NodeID string
|
|
Response []string
|
|
ExceptionType string
|
|
}
|
|
|
|
func (e Error) GetID() string { return e.ID }
|
|
func (e Error) Encode() ([]byte, error) {
|
|
return bencode.EncodeBytes(map[string]interface{}{
|
|
headerTypeField: errorType,
|
|
headerMessageIDField: e.ID,
|
|
headerNodeIDField: e.NodeID,
|
|
headerPayloadField: e.ExceptionType,
|
|
headerArgsField: e.Response,
|
|
})
|
|
}
|