/
piece.go
88 lines (75 loc) · 1.86 KB
/
piece.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package bytedribble
import (
"crypto/sha1"
"fmt"
)
type Piece struct {
Index uint32
Size uint32
BlockSize uint32
Hash [sha1.Size]byte
blocks [][]byte // blocks are views into payload
payload []byte
}
func (p *Piece) NumBlocks() int {
return int((p.Size + p.BlockSize - 1) / p.BlockSize)
}
func (p *Piece) block(idx int) Block {
if idx < 0 || idx >= p.NumBlocks() {
panic("invalid block index")
}
length := p.BlockSize
if idx == p.NumBlocks()-1 && p.Size%p.BlockSize != 0 {
length = p.Size % p.BlockSize
}
return Block{
PieceIndex: p.Index,
BeginOffset: uint32(idx) * p.BlockSize,
Length: length,
}
}
func (p *Piece) MissingBlocks() []Block {
if p.blocks == nil {
p.blocks = make([][]byte, p.NumBlocks(), p.NumBlocks())
}
var missing []Block
for idx, block := range p.blocks {
if block == nil {
missing = append(missing, p.block(idx))
}
}
return missing
}
func (p *Piece) AddBlockPayload(block Block, payload []byte) {
idx := int(block.BeginOffset / p.BlockSize)
if block != p.block(idx) {
panic("alien block")
}
if len(payload) != int(block.Length) {
panic("mismatched block length")
}
if p.blocks == nil {
p.blocks = make([][]byte, p.NumBlocks(), p.NumBlocks())
}
if p.payload == nil {
p.payload = make([]byte, p.Size, p.Size)
}
copy(p.payload[block.BeginOffset:block.BeginOffset+block.Length], payload)
p.blocks[idx] = p.payload[block.BeginOffset : block.BeginOffset+block.Length : block.BeginOffset+block.Length]
}
func (p *Piece) Valid() bool {
if len(p.MissingBlocks()) != 0 {
return false
}
return sha1.Sum(p.payload) == p.Hash
}
func (p *Piece) Payload() []byte {
return p.payload
}
func (p *Piece) String() string {
return fmt.Sprintf("{Index: %d; Size: %d; Hash: %v}", p.Index, p.Size, p.Hash)
}
func (p *Piece) Reset() {
p.blocks = nil
// keep p.payload around to avoid reallocating memory
}