client.go | 22 ++++++++++++++-------- fs/torrentfs.go | 5 ++++- torrent.go | 12 ++++++++++++ diff --git a/client.go b/client.go index 9b9a6d38e46fe30c7b0fd5f9548e95569a103077..6858f953b168893d50730cc6d9599077c13339e6 100644 --- a/client.go +++ b/client.go @@ -33,27 +33,32 @@ piece.QueuedForHash = true go cl.verifyPiece(t, pieceIndex) } -func (cl *Client) PrioritizeDataRegion(ih InfoHash, off, len_ int64) { +func (cl *Client) PrioritizeDataRegion(ih InfoHash, off, len_ int64) error { cl.mu.Lock() defer cl.mu.Unlock() t := cl.torrent(ih) - newPriorities := make([]Request, 0, (len_+2*(chunkSize-1))/chunkSize) + if t == nil { + return errors.New("no such active torrent") + } + newPriorities := make([]Request, 0, (len_+chunkSize-1)/chunkSize) for len_ > 0 { - // TODO: Write a function to return the Request for a given offset. req, ok := t.offsetRequest(off) if !ok { - break + return errors.New("bad offset") } - off += int64(req.Length) + reqOff := t.requestOffset(req) + // Gain the alignment adjustment. + len_ += off - reqOff + // Lose the length of this block. len_ -= int64(req.Length) - // TODO(anacrolix): Determine if this check is satisfactory. - if _, ok = t.Pieces[req.Index].PendingChunkSpecs[req.ChunkSpec]; !ok { + off = reqOff + int64(req.Length) + if !t.wantPiece(int(req.Index)) { continue } newPriorities = append(newPriorities, req) } if len(newPriorities) == 0 { - return + return nil } if t.Priorities == nil { t.Priorities = list.New() @@ -65,6 +70,7 @@ } for _, cn := range t.Conns { cl.replenishConnRequests(t, cn) } + return nil } type DataSpec struct { diff --git a/fs/torrentfs.go b/fs/torrentfs.go index 1c9567f09537a693213a3f250ae6ad6c46b9f7b3..fba0e09ecb4030baa083383cafb7cb5dd97cd1a8 100644 --- a/fs/torrentfs.go +++ b/fs/torrentfs.go @@ -65,7 +65,9 @@ } infoHash := torrent.BytesInfoHash(fn.metaInfo.InfoHash) torrentOff := fn.TorrentOffset + req.Offset log.Print(torrentOff, len(data), fn.TorrentOffset) - fn.FS.Client.PrioritizeDataRegion(infoHash, torrentOff, int64(len(data))) + if err := fn.FS.Client.PrioritizeDataRegion(infoHash, torrentOff, int64(len(data))); err != nil { + panic(err) + } for { dataWaiter := fn.FS.Client.DataWaiter() n, err := fn.FS.Client.TorrentReadAt(infoHash, torrentOff, data) @@ -217,6 +219,7 @@ Mode: os.ModeDir, } } +// TODO(anacrolix): Why should rootNode implement this? func (rootNode) Forget() { } diff --git a/torrent.go b/torrent.go index 5445eb97f1d221c488b7a1748a80c3175479d4d8..d6279f2dda626c226e29b26e1b3c9c713b2c0b48 100644 --- a/torrent.go +++ b/torrent.go @@ -92,6 +92,18 @@ ok = true return } +func torrentRequestOffset(torrentLength, pieceSize int64, r Request) (off int64) { + off = int64(r.Index)*pieceSize + int64(r.Begin) + if off < 0 || off >= torrentLength { + panic("invalid request") + } + return +} + +func (t *Torrent) requestOffset(r Request) int64 { + return torrentRequestOffset(t.Length(), t.MetaInfo.PieceLength, r) +} + // Return the request that would include the given offset into the torrent data. func (t *Torrent) offsetRequest(off int64) (req Request, ok bool) { return torrentOffsetRequest(t.Length(), t.MetaInfo.PieceLength, chunkSize, off)