]> Sergey Matveev's repositories - btrtrc.git/blob - misc.go
Rewrite import paths for migration from Bitbucket
[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         "github.com/anacrolix/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         PendingChunkSpecs map[chunkSpec]struct{}
49         Hashing           bool
50         QueuedForHash     bool
51         EverHashed        bool
52         Event             sync.Cond
53         Priority          piecePriority
54 }
55
56 func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) {
57         if len(p.PendingChunkSpecs) == 0 {
58                 return
59         }
60         css = make([]chunkSpec, 0, len(p.PendingChunkSpecs))
61         for cs := range p.PendingChunkSpecs {
62                 css = append(css, cs)
63         }
64         if len(css) <= 1 {
65                 return
66         }
67         for i := range css {
68                 j := rand.Intn(i + 1)
69                 css[i], css[j] = css[j], css[i]
70         }
71         return
72 }
73
74 func lastChunkSpec(pieceLength peer_protocol.Integer) (cs chunkSpec) {
75         cs.Begin = (pieceLength - 1) / chunkSize * chunkSize
76         cs.Length = pieceLength - cs.Begin
77         return
78 }
79
80 type chunkSpec struct {
81         Begin, Length peer_protocol.Integer
82 }
83
84 type request struct {
85         Index peer_protocol.Integer
86         chunkSpec
87 }
88
89 func newRequest(index, begin, length peer_protocol.Integer) request {
90         return request{index, chunkSpec{begin, length}}
91 }
92
93 var (
94         // Requested data not yet available.
95         errDataNotReady = errors.New("data not ready")
96 )
97
98 // The size in bytes of a metadata extension piece.
99 func metadataPieceSize(totalSize int, piece int) int {
100         ret := totalSize - piece*(1<<14)
101         if ret > 1<<14 {
102                 ret = 1 << 14
103         }
104         return ret
105 }
106
107 type Super interface {
108         Super() interface{}
109 }
110
111 // Returns ok if there's a parent, and it's not nil.
112 func super(child interface{}) (parent interface{}, ok bool) {
113         s, ok := child.(Super)
114         if !ok {
115                 return
116         }
117         parent = s.Super()
118         ok = parent != nil
119         return
120 }