From: Matt Joiner Date: Tue, 3 May 2016 06:47:11 +0000 (+1000) Subject: Move a bunch of Torrent methods from client.go X-Git-Tag: v1.0.0~756 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=f6b83130c9a7ff33d7136ad97d8b051e534d95d8;p=btrtrc.git Move a bunch of Torrent methods from client.go --- diff --git a/client.go b/client.go index 4f2e87ad..2c4655ab 100644 --- a/client.go +++ b/client.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "crypto/rand" - "crypto/sha1" "encoding/hex" "errors" "fmt" @@ -22,7 +21,6 @@ import ( "time" "github.com/anacrolix/missinggo" - "github.com/anacrolix/missinggo/bitmap" "github.com/anacrolix/missinggo/pproffd" "github.com/anacrolix/missinggo/pubsub" "github.com/anacrolix/sync" @@ -1006,44 +1004,6 @@ func (cl *Client) requestPendingMetadata(t *Torrent, c *connection) { } } -func (t *Torrent) maybeMetadataCompleted() { - if t.haveInfo() { - // Nothing to do. - return - } - if !t.haveAllMetadataPieces() { - // Don't have enough metadata pieces. - return - } - h := sha1.New() - h.Write(t.metadataBytes) - var ih metainfo.Hash - missinggo.CopyExact(&ih, h.Sum(nil)) - if ih != t.infoHash { - log.Printf("torrent %q: metadata bytes failed hash check", t) - t.invalidateMetadata() - return - } - var info metainfo.Info - err := bencode.Unmarshal(t.metadataBytes, &info) - if err != nil { - log.Printf("error unmarshalling metadata: %s", err) - t.invalidateMetadata() - return - } - // TODO(anacrolix): If this fails, I think something harsher should be - // done. - err = t.cl.setMetaData(t, &info, t.metadataBytes) - if err != nil { - log.Printf("error setting metadata: %s", err) - t.invalidateMetadata() - return - } - if t.cl.config.Debug { - log.Printf("%s: got metadata from peers", t) - } -} - // Process incoming ut_metadata message. func (cl *Client) gotMetadataExtensionMsg(payload []byte, t *Torrent, c *connection) (err error) { var d map[string]int @@ -1414,26 +1374,6 @@ func (cl *Client) addConnection(t *Torrent, c *connection) bool { return true } -func (t *Torrent) readerPieces() (ret bitmap.Bitmap) { - t.forReaderOffsetPieces(func(begin, end int) bool { - ret.AddRange(begin, end) - return true - }) - return -} - -func (t *Torrent) needData() bool { - if !t.haveInfo() { - return true - } - if t.pendingPieces.Len() != 0 { - return true - } - return !t.readerPieces().IterTyped(func(piece int) bool { - return t.pieceComplete(piece) - }) -} - func (cl *Client) usefulConn(t *Torrent, c *connection) bool { if c.closed.IsSet() { return false @@ -1603,27 +1543,6 @@ nextURL: return tier } -func (t *Torrent) addTrackers(announceList [][]string) { - newTrackers := copyTrackers(t.trackers) - for tierIndex, tier := range announceList { - if tierIndex < len(newTrackers) { - newTrackers[tierIndex] = mergeTier(newTrackers[tierIndex], tier) - } else { - newTrackers = append(newTrackers, mergeTier(nil, tier)) - } - shuffleTier(newTrackers[tierIndex]) - } - t.trackers = newTrackers -} - -// Don't call this before the info is available. -func (t *Torrent) bytesCompleted() int64 { - if !t.haveInfo() { - return 0 - } - return t.info.TotalLength() - t.bytesLeft() -} - // A file-like handle to some torrent data resource. type Handle interface { io.Reader @@ -1632,45 +1551,6 @@ type Handle interface { io.ReaderAt } -// Returns handles to the files in the torrent. This requires the metainfo is -// available first. -func (t *Torrent) Files() (ret []File) { - t.cl.mu.Lock() - info := t.Info() - t.cl.mu.Unlock() - if info == nil { - return - } - var offset int64 - for _, fi := range info.UpvertedFiles() { - ret = append(ret, File{ - t, - strings.Join(append([]string{info.Name}, fi.Path...), "/"), - offset, - fi.Length, - fi, - }) - offset += fi.Length - } - return -} - -func (t *Torrent) AddPeers(pp []Peer) error { - cl := t.cl - cl.mu.Lock() - defer cl.mu.Unlock() - cl.addPeers(t, pp) - return nil -} - -// Marks the entire torrent for download. Requires the info first, see -// GotInfo. -func (t *Torrent) DownloadAll() { - t.cl.mu.Lock() - defer t.cl.mu.Unlock() - t.pendPieceRange(0, t.numPieces()) -} - // Returns nil metainfo if it isn't in the cache. Checks that the retrieved // metainfo has the correct infohash. func (cl *Client) torrentCacheMetaInfo(ih metainfo.Hash) (mi *metainfo.MetaInfo, err error) { diff --git a/t.go b/t.go index eb292c91..3702e656 100644 --- a/t.go +++ b/t.go @@ -1,6 +1,9 @@ package torrent import ( + "fmt" + "strings" + "github.com/anacrolix/missinggo/pubsub" "github.com/anacrolix/torrent/metainfo" @@ -146,3 +149,50 @@ func (t *Torrent) CancelPieces(begin, end int) { defer t.cl.mu.Unlock() t.unpendPieceRange(begin, end) } + +// Returns handles to the files in the torrent. This requires the metainfo is +// available first. +func (t *Torrent) Files() (ret []File) { + t.cl.mu.Lock() + info := t.Info() + t.cl.mu.Unlock() + if info == nil { + return + } + var offset int64 + for _, fi := range info.UpvertedFiles() { + ret = append(ret, File{ + t, + strings.Join(append([]string{info.Name}, fi.Path...), "/"), + offset, + fi.Length, + fi, + }) + offset += fi.Length + } + return +} + +func (t *Torrent) AddPeers(pp []Peer) error { + cl := t.cl + cl.mu.Lock() + defer cl.mu.Unlock() + cl.addPeers(t, pp) + return nil +} + +// Marks the entire torrent for download. Requires the info first, see +// GotInfo. +func (t *Torrent) DownloadAll() { + t.cl.mu.Lock() + defer t.cl.mu.Unlock() + t.pendPieceRange(0, t.numPieces()) +} + +func (t *Torrent) String() string { + s := t.name() + if s == "" { + s = fmt.Sprintf("%x", t.infoHash) + } + return s +} diff --git a/torrent.go b/torrent.go index 834b315d..3680fc3d 100644 --- a/torrent.go +++ b/torrent.go @@ -2,6 +2,7 @@ package torrent import ( "container/heap" + "crypto/sha1" "fmt" "io" "log" @@ -452,14 +453,6 @@ func (t *Torrent) writeStatus(w io.Writer, cl *Client) { } } -func (t *Torrent) String() string { - s := t.name() - if s == "" { - s = fmt.Sprintf("%x", t.infoHash) - } - return s -} - func (t *Torrent) haveInfo() bool { return t.info != nil } @@ -1035,3 +1028,82 @@ func (t *Torrent) updateAllPieceCompletions() { t.updatePieceCompletion(i) } } + +func (t *Torrent) maybeMetadataCompleted() { + if t.haveInfo() { + // Nothing to do. + return + } + if !t.haveAllMetadataPieces() { + // Don't have enough metadata pieces. + return + } + h := sha1.New() + h.Write(t.metadataBytes) + var ih metainfo.Hash + missinggo.CopyExact(&ih, h.Sum(nil)) + if ih != t.infoHash { + log.Printf("torrent %q: metadata bytes failed hash check", t) + t.invalidateMetadata() + return + } + var info metainfo.Info + err := bencode.Unmarshal(t.metadataBytes, &info) + if err != nil { + log.Printf("error unmarshalling metadata: %s", err) + t.invalidateMetadata() + return + } + // TODO(anacrolix): If this fails, I think something harsher should be + // done. + err = t.cl.setMetaData(t, &info, t.metadataBytes) + if err != nil { + log.Printf("error setting metadata: %s", err) + t.invalidateMetadata() + return + } + if t.cl.config.Debug { + log.Printf("%s: got metadata from peers", t) + } +} + +func (t *Torrent) readerPieces() (ret bitmap.Bitmap) { + t.forReaderOffsetPieces(func(begin, end int) bool { + ret.AddRange(begin, end) + return true + }) + return +} + +func (t *Torrent) needData() bool { + if !t.haveInfo() { + return true + } + if t.pendingPieces.Len() != 0 { + return true + } + return !t.readerPieces().IterTyped(func(piece int) bool { + return t.pieceComplete(piece) + }) +} + +func (t *Torrent) addTrackers(announceList [][]string) { + newTrackers := copyTrackers(t.trackers) + for tierIndex, tier := range announceList { + if tierIndex < len(newTrackers) { + newTrackers[tierIndex] = mergeTier(newTrackers[tierIndex], tier) + } else { + newTrackers = append(newTrackers, mergeTier(nil, tier)) + } + shuffleTier(newTrackers[tierIndex]) + } + t.trackers = newTrackers +} + +// Don't call this before the info is available. +func (t *Torrent) bytesCompleted() int64 { + if !t.haveInfo() { + return 0 + } + return t.info.TotalLength() - t.bytesLeft() +}