* Implement BEP 40.
* Rewrite tracker package to be announce-centric, rather than client. Currently the clients are private and adapted onto by the Announce() func.
* Move tracker management code in the torrent package to its own file.
- * Optimize Reader.posChanged, it triggers all piece priorities to be recomputed.
"golang.org/x/net/context"
)
-// Accesses torrent data via a client.
+// Piece range by piece index, [begin, end).
+type pieceRange struct {
+ begin, end int
+}
+
+// Accesses Torrent data via a Client. Reads block until the data is
+// available. Seeks and readahead also drive Client behaviour.
type Reader struct {
t *Torrent
responsive bool
mu sync.Locker
pos int64
readahead int64
+ // The cached piece range this reader wants downloaded. The zero value
+ // corresponds to nothing. We cache this so that changes can be detected,
+ // and bubbled up to the Torrent only as required.
+ pieces pieceRange
}
var _ io.ReadCloser = &Reader{}
r.t.cl.event.Wait()
}
+// Calculates the pieces this reader wants downloaded, ignoring the cached
+// value at r.pieces.
+func (r *Reader) piecesUncached() (ret pieceRange) {
+ ra := r.readahead
+ if ra < 1 {
+ ra = 1
+ }
+ ret.begin, ret.end = r.t.byteRegionPieces(r.pos, ra)
+ return
+}
+
func (r *Reader) Read(b []byte) (n int, err error) {
return r.ReadContext(b, context.Background())
}
}
func (r *Reader) posChanged() {
+ p := r.piecesUncached()
+ if p == r.pieces {
+ return
+ }
+ r.pieces = p
r.t.readersChanged()
}
}
}
+// Returns the range of pieces [begin, end) that contains the extent of bytes.
func (t *Torrent) byteRegionPieces(off, size int64) (begin, end int) {
if off >= t.length {
return
// callers depend on this method to enumerate readers.
func (t *Torrent) forReaderOffsetPieces(f func(begin, end int) (more bool)) (all bool) {
for r := range t.readers {
- // r.mu.Lock()
- pos, readahead := r.pos, r.readahead
- // r.mu.Unlock()
- if readahead < 1 {
- readahead = 1
- }
- begin, end := t.byteRegionPieces(pos, readahead)
- if begin >= end {
+ p := r.pieces
+ if p.begin >= p.end {
continue
}
- if !f(begin, end) {
+ if !f(p.begin, p.end) {
return false
}
}