11 // Accesses torrent data via a client.
21 var _ io.ReadCloser = &Reader{}
23 // Don't wait for pieces to complete and be verified. Read calls return as
24 // soon as they can when the underlying chunks become available.
25 func (r *Reader) SetResponsive() {
29 // Configure the number of bytes ahead of a read that should also be
30 // prioritized in preparation for further reads.
31 func (r *Reader) SetReadahead(readahead int64) {
34 r.readahead = readahead
37 func (r *Reader) readable(off int64) (ret bool) {
38 if r.torrentClosed() {
41 req, ok := r.t.torrent.offsetRequest(off)
46 return r.t.torrent.haveChunk(req)
48 return r.t.torrent.pieceComplete(int(req.Index))
51 // How many bytes are available to read. Max is the most we could require.
52 func (r *Reader) available(off, max int64) (ret int64) {
54 req, ok := r.t.torrent.offsetRequest(off)
58 if !r.t.torrent.haveChunk(req) {
61 len1 := int64(req.Length) - (off - r.t.torrent.requestOffset(req))
66 // Ensure that ret hasn't exceeded our original max.
73 func (r *Reader) tickleClient() {
74 r.t.torrent.readersChanged()
77 func (r *Reader) waitReadable(off int64) {
78 // We may have been sent back here because we were told we could read but
84 func (r *Reader) Read(b []byte) (n int, err error) {
88 n, err = r.readAt(b, pos)
96 // Safe to call with or without client lock.
97 func (r *Reader) torrentClosed() bool {
98 return r.t.torrent.isClosed()
101 // Wait until some data should be available to read. Tickles the client if it
102 // isn't. Returns how much should be readable without blocking.
103 func (r *Reader) waitAvailable(pos, wanted int64) (avail int64) {
105 defer r.t.cl.mu.Unlock()
106 for !r.readable(pos) {
109 return r.available(pos, wanted)
112 // Performs at most one successful read to torrent storage.
113 func (r *Reader) readOnceAt(b []byte, pos int64) (n int, err error) {
114 if pos >= r.t.torrent.length {
119 avail := r.waitAvailable(pos, int64(len(b)))
121 if r.torrentClosed() {
122 err = errors.New("torrent closed")
127 pi := int(pos / r.t.Info().PieceLength)
128 ip := r.t.Info().Piece(pi)
129 po := pos % ip.Length()
130 if int64(len(b1)) > ip.Length()-po {
131 b1 = b1[:ip.Length()-po]
133 n, err = r.t.torrent.readAt(b1, pos)
137 log.Printf("%s: error reading from torrent storage pos=%d: %s", r.t, pos, err)
139 r.t.torrent.updatePieceCompletion(pi)
140 r.t.torrent.updatePiecePriority(pi)
145 // Must only return EOF at the end of the torrent. Fills b until error or
146 // valid EOF. Note that the Reader pos is not updated until the read
147 // completes, this may reduce piece priority recalculation, but also the
148 // effectiveness of readahead.
149 func (r *Reader) readAt(b []byte, pos int64) (n int, err error) {
152 n1, err = r.readOnceAt(b, pos)
155 panic("expected error")
163 if pos >= r.t.torrent.length {
165 } else if err == io.EOF {
166 err = io.ErrUnexpectedEOF
171 func (r *Reader) Close() error {
177 func (r *Reader) posChanged() {
179 defer r.t.cl.mu.Unlock()
180 r.t.torrent.readersChanged()
183 func (r *Reader) Seek(off int64, whence int) (ret int64, err error) {
191 r.pos = r.t.torrent.Info.TotalLength() + off
193 err = errors.New("bad whence")