"io"
"os"
- "github.com/anacrolix/missinggo"
+ "github.com/anacrolix/missinggo/v2"
"github.com/anacrolix/torrent/metainfo"
)
func (cl Client) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (*Torrent, error) {
t, err := cl.ci.OpenTorrent(info, infoHash)
- return &Torrent{t}, err
+ if err != nil {
+ return nil, err
+ }
+ return &Torrent{t}, nil
}
type Torrent struct {
mip metainfo.Piece
}
+var _ io.WriterTo = Piece{}
+
+// Why do we have this wrapper? Well PieceImpl doesn't implement io.Reader, so we can't let io.Copy
+// and friends check for io.WriterTo and fallback for us since they expect an io.Reader.
+func (p Piece) WriteTo(w io.Writer) (int64, error) {
+ if i, ok := p.PieceImpl.(io.WriterTo); ok {
+ return i.WriteTo(w)
+ }
+ n := p.mip.Length()
+ r := io.NewSectionReader(p, 0, n)
+ return io.CopyN(w, r, n)
+}
+
func (p Piece) WriteAt(b []byte, off int64) (n int, err error) {
// Callers should not be writing to completed pieces, but it's too
// expensive to be checking this on every single write using uncached
if n > len(b) {
panic(n)
}
- off += int64(n)
- if err == io.EOF && off < p.mip.Length() {
- err = io.ErrUnexpectedEOF
- }
- if err == nil && off >= p.mip.Length() {
- err = io.EOF
- }
if n == 0 && err == nil {
- err = io.ErrUnexpectedEOF
+ panic("io.Copy will get stuck")
}
- if off < p.mip.Length() && err != nil {
- p.MarkNotComplete()
+ off += int64(n)
+
+ // Doing this here may be inaccurate. There's legitimate reasons we may fail to read while the
+ // data is still there, such as too many open files. There should probably be a specific error
+ // to return if the data has been lost.
+ if off < p.mip.Length() {
+ if err == io.EOF {
+ p.MarkNotComplete()
+ }
}
+
return
}