github.com/anacrolix/torrent@v1.61.0/storage.go (about)

     1  package torrent
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/anacrolix/missinggo/v2/panicif"
     7  
     8  	"github.com/anacrolix/torrent/storage"
     9  )
    10  
    11  func (t *Torrent) storageReader() storageReader {
    12  	if t.storage.NewReader == nil {
    13  		return &storagePieceReader{t: t}
    14  	}
    15  	return torrentStorageImplReader{
    16  		implReader: t.storage.NewReader(),
    17  		t:          t,
    18  	}
    19  }
    20  
    21  // This wraps per-piece storage as a whole-torrent storageReader.
    22  type storagePieceReader struct {
    23  	t       *Torrent
    24  	pr      storage.PieceReader
    25  	prIndex int
    26  }
    27  
    28  func (me *storagePieceReader) Close() (err error) {
    29  	if me.pr != nil {
    30  		err = me.pr.Close()
    31  	}
    32  	return
    33  }
    34  
    35  func (me *storagePieceReader) getReaderAt(p *Piece) (err error) {
    36  	if me.pr != nil {
    37  		if me.prIndex == p.index {
    38  			return
    39  		}
    40  		panicif.Err(me.pr.Close())
    41  		me.pr = nil
    42  	}
    43  	ps := p.Storage()
    44  	me.prIndex = p.index
    45  	me.pr, err = ps.NewReader()
    46  	return
    47  }
    48  
    49  func (me *storagePieceReader) ReadAt(b []byte, off int64) (n int, err error) {
    50  	for len(b) != 0 {
    51  		p := me.t.pieceForOffset(off)
    52  		p.waitNoPendingWrites()
    53  		var n1 int
    54  		err = me.getReaderAt(p)
    55  		if err != nil {
    56  			return
    57  		}
    58  		n1, err = me.pr.ReadAt(b, off-p.Info().Offset())
    59  		if n1 == 0 {
    60  			panicif.Nil(err)
    61  			break
    62  		}
    63  		off += int64(n1)
    64  		n += n1
    65  		b = b[n1:]
    66  	}
    67  	return
    68  }
    69  
    70  type storageReader interface {
    71  	io.ReaderAt
    72  	io.Closer
    73  }
    74  
    75  // This wraps a storage impl provided TorrentReader as a storageReader.
    76  type torrentStorageImplReader struct {
    77  	implReader storage.TorrentReader
    78  	t          *Torrent
    79  }
    80  
    81  func (me torrentStorageImplReader) ReadAt(p []byte, off int64) (n int, err error) {
    82  	// TODO: Should waitNoPendingWrites take a region?
    83  	me.t.pieceForOffset(off).waitNoPendingWrites()
    84  	return me.implReader.ReadAt(p, off)
    85  }
    86  
    87  func (me torrentStorageImplReader) Close() error {
    88  	return me.implReader.Close()
    89  }