7 g "github.com/anacrolix/generics"
8 "github.com/anacrolix/missinggo/v2"
10 "github.com/anacrolix/torrent/metainfo"
17 func NewClient(cl ClientImpl) *Client {
21 func (cl Client) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (*Torrent, error) {
22 t, err := cl.ci.OpenTorrent(info, infoHash)
26 return &Torrent{t}, nil
33 // Deprecated. Use PieceWithHash, as this doesn't work with pure v2 torrents.
34 func (t Torrent) Piece(p metainfo.Piece) Piece {
35 return t.PieceWithHash(p, g.Some(p.V1Hash().Unwrap().Bytes()))
38 func (t Torrent) PieceWithHash(p metainfo.Piece, pieceHash g.Option[[]byte]) Piece {
39 var pieceImpl PieceImpl
40 if t.TorrentImpl.PieceWithHash != nil {
41 pieceImpl = t.TorrentImpl.PieceWithHash(p, pieceHash)
43 pieceImpl = t.TorrentImpl.Piece(p)
45 return Piece{pieceImpl, p}
53 var _ io.WriterTo = Piece{}
55 // Why do we have this wrapper? Well PieceImpl doesn't implement io.Reader, so we can't let io.Copy
56 // and friends check for io.WriterTo and fallback for us since they expect an io.Reader.
57 func (p Piece) WriteTo(w io.Writer) (int64, error) {
58 if i, ok := p.PieceImpl.(io.WriterTo); ok {
62 r := io.NewSectionReader(p, 0, n)
63 return io.CopyN(w, r, n)
66 func (p Piece) WriteAt(b []byte, off int64) (n int, err error) {
67 // Callers should not be writing to completed pieces, but it's too
68 // expensive to be checking this on every single write using uncached
71 // c := p.Completion()
72 // if c.Ok && c.Complete {
73 // err = errors.New("piece already completed")
76 if off+int64(len(b)) > p.mip.Length() {
77 panic("write overflows piece")
79 b = missinggo.LimitLen(b, p.mip.Length()-off)
80 return p.PieceImpl.WriteAt(b, off)
83 func (p Piece) ReadAt(b []byte, off int64) (n int, err error) {
88 if off >= p.mip.Length() {
92 b = missinggo.LimitLen(b, p.mip.Length()-off)
96 n, err = p.PieceImpl.ReadAt(b, off)
100 if n == 0 && err == nil {
101 panic("io.Copy will get stuck")
105 // Doing this here may be inaccurate. There's legitimate reasons we may fail to read while the
106 // data is still there, such as too many open files. There should probably be a specific error
107 // to return if the data has been lost.
108 if off < p.mip.Length() {