1 package rifs 2 3 import ( 4 "io" 5 6 "github.com/dsoprea/go-logging" 7 ) 8 9 // ReadSeekerToReaderAt is a wrapper that allows a ReadSeeker to masquerade as a 10 // ReaderAt. 11 type ReadSeekerToReaderAt struct { 12 rs io.ReadSeeker 13 } 14 15 // NewReadSeekerToReaderAt returns a new ReadSeekerToReaderAt instance. 16 func NewReadSeekerToReaderAt(rs io.ReadSeeker) *ReadSeekerToReaderAt { 17 return &ReadSeekerToReaderAt{ 18 rs: rs, 19 } 20 } 21 22 // ReadAt is a wrapper that satisfies the ReaderAt interface. 23 // 24 // Note that a requirement of ReadAt is that it doesn't have an effect on the 25 // offset in the underlying resource as well as that concurrent calls can be 26 // made to it. Since we're capturing the current offset in the underlying 27 // resource and then seeking back to it before returning, it is the 28 // responsibility of the caller to serialize (i.e. use a mutex with) these 29 // requests in order to eliminate race-conditions in the parallel-usage 30 // scenario. 31 // 32 // Note also that, since ReadAt() is going to be called on a particular 33 // instance, that instance is going to internalize a file resource, that file- 34 // resource is provided by the OS, and [most] OSs are only gonna support one 35 // file-position per resource, locking is already going to be a necessary 36 // internal semantic of a ReaderAt implementation. 37 func (rstra *ReadSeekerToReaderAt) ReadAt(p []byte, offset int64) (n int, err error) { 38 defer func() { 39 if state := recover(); state != nil { 40 err = log.Wrap(state.(error)) 41 } 42 }() 43 44 originalOffset, err := rstra.rs.Seek(0, io.SeekCurrent) 45 log.PanicIf(err) 46 47 defer func() { 48 _, err := rstra.rs.Seek(originalOffset, io.SeekStart) 49 log.PanicIf(err) 50 }() 51 52 _, err = rstra.rs.Seek(offset, io.SeekStart) 53 log.PanicIf(err) 54 55 // Note that all errors will be wrapped, here. The usage of this method is 56 // such that typically no specific errors would be expected as part of 57 // normal operation (in which case we'd check for those first and return 58 // them directly). 59 n, err = io.ReadFull(rstra.rs, p) 60 log.PanicIf(err) 61 62 return n, nil 63 } 64