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 }