]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Make blob data stateful
[btrtrc.git] / misc.go
1 package torrent
2
3 import (
4         "crypto"
5         "errors"
6         "fmt"
7         "math/rand"
8         "sync"
9         "time"
10
11         "bitbucket.org/anacrolix/go.torrent/peer_protocol"
12 )
13
14 const (
15         pieceHash          = crypto.SHA1
16         maxRequests        = 250        // Maximum pending requests we allow peers to send us.
17         chunkSize          = 0x4000     // 16KiB
18         BEP20              = "-GT0000-" // Peer ID client identifier prefix
19         nominalDialTimeout = time.Second * 30
20         minDialTimeout     = 5 * time.Second
21 )
22
23 type (
24         InfoHash [20]byte
25         pieceSum [20]byte
26 )
27
28 func (ih *InfoHash) AsString() string {
29         return string(ih[:])
30 }
31
32 func (ih *InfoHash) HexString() string {
33         return fmt.Sprintf("%x", ih[:])
34 }
35
36 type piecePriority byte
37
38 const (
39         piecePriorityNone piecePriority = iota
40         piecePriorityNormal
41         piecePriorityReadahead
42         piecePriorityNext
43         piecePriorityNow
44 )
45
46 type piece struct {
47         Hash              pieceSum
48         complete          bool
49         PendingChunkSpecs map[chunkSpec]struct{}
50         Hashing           bool
51         QueuedForHash     bool
52         EverHashed        bool
53         Event             sync.Cond
54         Priority          piecePriority
55 }
56
57 func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) {
58         if len(p.PendingChunkSpecs) == 0 {
59                 return
60         }
61         css = make([]chunkSpec, 0, len(p.PendingChunkSpecs))
62         for cs := range p.PendingChunkSpecs {
63                 css = append(css, cs)
64         }
65         if len(css) <= 1 {
66                 return
67         }
68         for i := range css {
69                 j := rand.Intn(i + 1)
70                 css[i], css[j] = css[j], css[i]
71         }
72         return
73 }
74
75 func (p *piece) Complete() bool {
76         return p.complete
77 }
78
79 func lastChunkSpec(pieceLength peer_protocol.Integer) (cs chunkSpec) {
80         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
81         cs.Length = pieceLength - cs.Begin
82         return
83 }
84
85 type chunkSpec struct {
86         Begin, Length peer_protocol.Integer
87 }
88
89 type request struct {
90         Index peer_protocol.Integer
91         chunkSpec
92 }
93
94 func newRequest(index, begin, length peer_protocol.Integer) request {
95         return request{index, chunkSpec{begin, length}}
96 }
97
98 var (
99         // Requested data not yet available.
100         ErrDataNotReady = errors.New("data not ready")
101 )
102
103 // The size in bytes of a metadata extension piece.
104 func metadataPieceSize(totalSize int, piece int) int {
105         ret := totalSize - piece*(1<<14)
106         if ret > 1<<14 {
107                 ret = 1 << 14
108         }
109         return ret
110 }