155 lines
2.6 KiB
Go
155 lines
2.6 KiB
Go
package dht
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
|
|
"github.com/lbryio/errors.go"
|
|
"github.com/lyoshenka/bencode"
|
|
)
|
|
|
|
type Bitmap [nodeIDLength]byte
|
|
|
|
func (b Bitmap) RawString() string {
|
|
return string(b[:])
|
|
}
|
|
|
|
func (b Bitmap) Hex() string {
|
|
return hex.EncodeToString(b[:])
|
|
}
|
|
|
|
func (b Bitmap) HexShort() string {
|
|
return hex.EncodeToString(b[:4])
|
|
}
|
|
|
|
func (b Bitmap) Equals(other Bitmap) bool {
|
|
for k := range b {
|
|
if b[k] != other[k] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (b Bitmap) Less(other interface{}) bool {
|
|
for k := range b {
|
|
if b[k] != other.(Bitmap)[k] {
|
|
return b[k] < other.(Bitmap)[k]
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b Bitmap) Xor(other Bitmap) Bitmap {
|
|
var ret Bitmap
|
|
for k := range b {
|
|
ret[k] = b[k] ^ other[k]
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// PrefixLen returns the number of leading 0 bits
|
|
func (b Bitmap) PrefixLen() int {
|
|
for i := range b {
|
|
for j := 0; j < 8; j++ {
|
|
if (b[i]>>uint8(7-j))&0x1 != 0 {
|
|
return i*8 + j
|
|
}
|
|
}
|
|
}
|
|
return numBuckets
|
|
}
|
|
|
|
// ZeroPrefix returns a copy of b with the first n bits set to 0
|
|
// https://stackoverflow.com/a/23192263/182709
|
|
func (b Bitmap) ZeroPrefix(n int) Bitmap {
|
|
var ret Bitmap
|
|
copy(ret[:], b[:])
|
|
|
|
Outer:
|
|
for i := range ret {
|
|
for j := 0; j < 8; j++ {
|
|
if i*8+j < n {
|
|
ret[i] &= ^(1 << uint(7-j))
|
|
} else {
|
|
break Outer
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (b Bitmap) MarshalBencode() ([]byte, error) {
|
|
str := string(b[:])
|
|
return bencode.EncodeBytes(str)
|
|
}
|
|
|
|
func (b *Bitmap) UnmarshalBencode(encoded []byte) error {
|
|
var str string
|
|
err := bencode.DecodeBytes(encoded, &str)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(str) != nodeIDLength {
|
|
return errors.Err("invalid bitmap length")
|
|
}
|
|
copy(b[:], str)
|
|
return nil
|
|
}
|
|
|
|
func BitmapFromBytes(data []byte) (Bitmap, error) {
|
|
var bmp Bitmap
|
|
|
|
if len(data) != len(bmp) {
|
|
return bmp, errors.Err("invalid bitmap of length %d", len(data))
|
|
}
|
|
|
|
copy(bmp[:], data)
|
|
return bmp, nil
|
|
}
|
|
|
|
func BitmapFromBytesP(data []byte) Bitmap {
|
|
bmp, err := BitmapFromBytes(data)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return bmp
|
|
}
|
|
|
|
func BitmapFromString(data string) (Bitmap, error) {
|
|
return BitmapFromBytes([]byte(data))
|
|
}
|
|
|
|
func BitmapFromStringP(data string) Bitmap {
|
|
bmp, err := BitmapFromString(data)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return bmp
|
|
}
|
|
|
|
func BitmapFromHex(hexStr string) (Bitmap, error) {
|
|
decoded, err := hex.DecodeString(hexStr)
|
|
if err != nil {
|
|
return Bitmap{}, errors.Err(err)
|
|
}
|
|
return BitmapFromBytes(decoded)
|
|
}
|
|
|
|
func BitmapFromHexP(hexStr string) Bitmap {
|
|
bmp, err := BitmapFromHex(hexStr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return bmp
|
|
}
|
|
|
|
func RandomBitmapP() Bitmap {
|
|
var id Bitmap
|
|
_, err := rand.Read(id[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return id
|
|
}
|