forked from anacrolix/torrent
-
Notifications
You must be signed in to change notification settings - Fork 1
/
t.go
242 lines (209 loc) · 6 KB
/
t.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package torrent
import (
"strconv"
"strings"
"github.com/anacrolix/missinggo/pubsub"
"github.com/anacrolix/torrent/metainfo"
)
// The torrent's infohash. This is fixed and cannot change. It uniquely
// identifies a torrent.
func (t *Torrent) InfoHash() metainfo.Hash {
return t.infoHash
}
// Returns a channel that is closed when the info (.Info()) for the torrent
// has become available.
func (t *Torrent) GotInfo() <-chan struct{} {
t.cl.lock()
defer t.cl.unlock()
return t.gotMetainfo.C()
}
// Returns the metainfo info dictionary, or nil if it's not yet available.
func (t *Torrent) Info() *metainfo.Info {
t.cl.lock()
defer t.cl.unlock()
return t.info
}
// Returns a Reader bound to the torrent's data. All read calls block until
// the data requested is actually available.
func (t *Torrent) NewReader() Reader {
r := reader{
mu: t.cl.locker(),
t: t,
readahead: 5 * 1024 * 1024,
length: *t.length,
}
t.addReader(&r)
return &r
}
// Returns the state of pieces of the torrent. They are grouped into runs of
// same state. The sum of the state run lengths is the number of pieces
// in the torrent.
func (t *Torrent) PieceStateRuns() []PieceStateRun {
t.cl.rLock()
defer t.cl.rUnlock()
return t.pieceStateRuns()
}
func (t *Torrent) PieceState(piece pieceIndex) PieceState {
t.cl.rLock()
defer t.cl.rUnlock()
return t.pieceState(piece)
}
// The number of pieces in the torrent. This requires that the info has been
// obtained first.
func (t *Torrent) NumPieces() pieceIndex {
return t.numPieces()
}
// Get missing bytes count for specific piece.
func (t *Torrent) PieceBytesMissing(piece int) int64 {
t.cl.lock()
defer t.cl.unlock()
return int64(t.pieces[piece].bytesLeft())
}
// Drop the torrent from the client, and close it. It's always safe to do
// this. No data corruption can, or should occur to either the torrent's data,
// or connected peers.
func (t *Torrent) Drop() {
t.cl.lock()
t.cl.dropTorrent(t.infoHash)
t.cl.unlock()
}
// Number of bytes of the entire torrent we have completed. This is the sum of
// completed pieces, and dirtied chunks of incomplete pieces. Do not use this
// for download rate, as it can go down when pieces are lost or fail checks.
// Sample Torrent.Stats.DataBytesRead for actual file data download rate.
func (t *Torrent) BytesCompleted() int64 {
t.cl.rLock()
defer t.cl.rUnlock()
return t.bytesCompleted()
}
// The subscription emits as (int) the index of pieces as their state changes.
// A state change is when the PieceState for a piece alters in value.
func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription {
return t.pieceStateChanges.Subscribe()
}
// Returns true if the torrent is currently being seeded. This occurs when the
// client is willing to upload without wanting anything in return.
func (t *Torrent) Seeding() bool {
t.cl.lock()
defer t.cl.unlock()
return t.seeding()
}
// Clobbers the torrent display name. The display name is used as the torrent
// name if the metainfo is not available.
func (t *Torrent) SetDisplayName(dn string) {
t.nameMu.Lock()
defer t.nameMu.Unlock()
if t.haveInfo() {
return
}
t.displayName = dn
}
// The current working name for the torrent. Either the name in the info dict,
// or a display name given such as by the dn value in a magnet link, or "".
func (t *Torrent) Name() string {
return t.name()
}
// The completed length of all the torrent data, in all its files. This is
// derived from the torrent info, when it is available.
func (t *Torrent) Length() int64 {
return *t.length
}
// Returns a run-time generated metainfo for the torrent that includes the
// info bytes and announce-list as currently known to the client.
func (t *Torrent) Metainfo() metainfo.MetaInfo {
t.cl.lock()
defer t.cl.unlock()
return t.newMetaInfo()
}
func (t *Torrent) addReader(r *reader) {
t.cl.lock()
defer t.cl.unlock()
if t.readers == nil {
t.readers = make(map[*reader]struct{})
}
t.readers[r] = struct{}{}
r.posChanged()
}
func (t *Torrent) deleteReader(r *reader) {
delete(t.readers, r)
t.readersChanged()
}
// Raise the priorities of pieces in the range [begin, end) to at least Normal
// priority. Piece indexes are not the same as bytes. Requires that the info
// has been obtained, see Torrent.Info and Torrent.GotInfo.
func (t *Torrent) DownloadPieces(begin, end pieceIndex) {
t.cl.lock()
defer t.cl.unlock()
t.downloadPiecesLocked(begin, end)
}
func (t *Torrent) downloadPiecesLocked(begin, end pieceIndex) {
for i := begin; i < end; i++ {
if t.pieces[i].priority.Raise(PiecePriorityNormal) {
t.updatePiecePriority(i)
}
}
}
func (t *Torrent) CancelPieces(begin, end pieceIndex) {
t.cl.lock()
defer t.cl.unlock()
t.cancelPiecesLocked(begin, end)
}
func (t *Torrent) cancelPiecesLocked(begin, end pieceIndex) {
for i := begin; i < end; i++ {
p := &t.pieces[i]
if p.priority == PiecePriorityNone {
continue
}
p.priority = PiecePriorityNone
t.updatePiecePriority(i)
}
}
func (t *Torrent) initFiles() {
var offset int64
t.files = new([]*File)
for _, fi := range t.info.UpvertedFiles() {
*t.files = append(*t.files, &File{
t,
strings.Join(append([]string{t.info.Name}, fi.Path...), "/"),
offset,
fi.Length,
fi,
PiecePriorityNone,
})
offset += fi.Length
}
}
// Returns handles to the files in the torrent. This requires that the Info is
// available first.
func (t *Torrent) Files() []*File {
return *t.files
}
func (t *Torrent) AddPeers(pp []Peer) {
cl := t.cl
cl.lock()
defer cl.unlock()
t.addPeers(pp)
}
// Marks the entire torrent for download. Requires the info first, see
// GotInfo. Sets piece priorities for historical reasons.
func (t *Torrent) DownloadAll() {
t.DownloadPieces(0, t.numPieces())
}
func (t *Torrent) String() string {
s := t.name()
if s == "" {
return t.infoHash.HexString()
} else {
return strconv.Quote(s)
}
}
func (t *Torrent) AddTrackers(announceList [][]string) {
t.cl.lock()
defer t.cl.unlock()
t.addTrackers(announceList)
}
func (t *Torrent) Piece(i pieceIndex) *Piece {
t.cl.lock()
defer t.cl.unlock()
return &t.pieces[i]
}