]> Sergey Matveev's repositories - btrtrc.git/blobdiff - t.go
Drop support for go 1.20
[btrtrc.git] / t.go
diff --git a/t.go b/t.go
index 043262066fe8a73b4d30e8f7c2a2ed14b065ab1a..45856cc7acbeaa5988074f74435d078a49111a57 100644 (file)
--- a/t.go
+++ b/t.go
@@ -1,59 +1,81 @@
 package torrent
 
 import (
+       "strconv"
        "strings"
 
-       "github.com/anacrolix/missinggo/pubsub"
+       "github.com/anacrolix/chansync/events"
+       "github.com/anacrolix/missinggo/v2/pubsub"
+       "github.com/anacrolix/sync"
+
        "github.com/anacrolix/torrent/metainfo"
 )
 
-// The torrent's infohash. This is fixed and cannot change. It uniquely
-// identifies a torrent.
+// The Torrent's infohash. This is fixed and cannot change. It uniquely identifies a torrent.
 func (t *Torrent) InfoHash() metainfo.Hash {
        return t.infoHash
 }
 
-// Returns a channel that is closed when the info (.Info()) for the torrent
-// has become available.
-func (t *Torrent) GotInfo() <-chan struct{} {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return t.gotMetainfo.C()
+// Returns a channel that is closed when the info (.Info()) for the torrent has become available.
+func (t *Torrent) GotInfo() events.Done {
+       return t.gotMetainfoC
 }
 
 // Returns the metainfo info dictionary, or nil if it's not yet available.
-func (t *Torrent) Info() *metainfo.Info {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return t.info
+func (t *Torrent) Info() (info *metainfo.Info) {
+       t.nameMu.RLock()
+       info = t.info
+       t.nameMu.RUnlock()
+       return
 }
 
-// Returns a Reader bound to the torrent's data. All read calls block until
-// the data requested is actually available.
+// Returns a Reader bound to the torrent's data. All read calls block until the data requested is
+// actually available. Note that you probably want to ensure the Torrent Info is available first.
 func (t *Torrent) NewReader() Reader {
+       return t.newReader(0, t.length())
+}
+
+func (t *Torrent) newReader(offset, length int64) Reader {
        r := reader{
-               mu:        t.cl.locker(),
-               t:         t,
-               readahead: 5 * 1024 * 1024,
-               length:    *t.length,
+               mu:     t.cl.locker(),
+               t:      t,
+               offset: offset,
+               length: length,
        }
+       r.readaheadFunc = defaultReadaheadFunc
        t.addReader(&r)
        return &r
 }
 
-// Returns the state of pieces of the torrent. They are grouped into runs of
-// same state. The sum of the state run lengths is the number of pieces
-// in the torrent.
-func (t *Torrent) PieceStateRuns() []PieceStateRun {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return t.pieceStateRuns()
+type PieceStateRuns []PieceStateRun
+
+func (me PieceStateRuns) String() (s string) {
+       if len(me) > 0 {
+               var sb strings.Builder
+               sb.WriteString(me[0].String())
+               for i := 1; i < len(me); i += 1 {
+                       sb.WriteByte(' ')
+                       sb.WriteString(me[i].String())
+               }
+               return sb.String()
+       }
+       return
 }
 
-func (t *Torrent) PieceState(piece pieceIndex) PieceState {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return t.pieceState(piece)
+// Returns the state of pieces of the torrent. They are grouped into runs of same state. The sum of
+// the state run-lengths is the number of pieces in the torrent.
+func (t *Torrent) PieceStateRuns() (runs PieceStateRuns) {
+       t.cl.rLock()
+       runs = t.pieceStateRuns()
+       t.cl.rUnlock()
+       return
+}
+
+func (t *Torrent) PieceState(piece pieceIndex) (ps PieceState) {
+       t.cl.rLock()
+       ps = t.pieceState(piece)
+       t.cl.rUnlock()
+       return
 }
 
 // The number of pieces in the torrent. This requires that the info has been
@@ -64,8 +86,8 @@ func (t *Torrent) NumPieces() pieceIndex {
 
 // Get missing bytes count for specific piece.
 func (t *Torrent) PieceBytesMissing(piece int) int64 {
-       t.cl.lock()
-       defer t.cl.unlock()
+       t.cl.rLock()
+       defer t.cl.rUnlock()
 
        return int64(t.pieces[piece].bytesLeft())
 }
@@ -74,9 +96,14 @@ func (t *Torrent) PieceBytesMissing(piece int) int64 {
 // this. No data corruption can, or should occur to either the torrent's data,
 // or connected peers.
 func (t *Torrent) Drop() {
+       var wg sync.WaitGroup
+       defer wg.Wait()
        t.cl.lock()
-       t.cl.dropTorrent(t.infoHash)
-       t.cl.unlock()
+       defer t.cl.unlock()
+       err := t.cl.dropTorrent(t.infoHash, &wg)
+       if err != nil {
+               panic(err)
+       }
 }
 
 // Number of bytes of the entire torrent we have completed. This is the sum of
@@ -91,45 +118,46 @@ func (t *Torrent) BytesCompleted() int64 {
 
 // The subscription emits as (int) the index of pieces as their state changes.
 // A state change is when the PieceState for a piece alters in value.
-func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription {
+func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription[PieceStateChange] {
        return t.pieceStateChanges.Subscribe()
 }
 
 // Returns true if the torrent is currently being seeded. This occurs when the
 // client is willing to upload without wanting anything in return.
-func (t *Torrent) Seeding() bool {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return t.seeding()
+func (t *Torrent) Seeding() (ret bool) {
+       t.cl.rLock()
+       ret = t.seeding()
+       t.cl.rUnlock()
+       return
 }
 
-// Clobbers the torrent display name. The display name is used as the torrent
-// name if the metainfo is not available.
+// Clobbers the torrent display name if metainfo is unavailable.
+// The display name is used as the torrent name while the metainfo is unavailable.
 func (t *Torrent) SetDisplayName(dn string) {
-       t.cl.lock()
-       defer t.cl.unlock()
-       t.setDisplayName(dn)
+       t.nameMu.Lock()
+       if !t.haveInfo() {
+               t.displayName = dn
+       }
+       t.nameMu.Unlock()
 }
 
 // The current working name for the torrent. Either the name in the info dict,
 // or a display name given such as by the dn value in a magnet link, or "".
 func (t *Torrent) Name() string {
-       t.cl.lock()
-       defer t.cl.unlock()
        return t.name()
 }
 
 // The completed length of all the torrent data, in all its files. This is
 // derived from the torrent info, when it is available.
 func (t *Torrent) Length() int64 {
-       return *t.length
+       return t._length.Value
 }
 
 // Returns a run-time generated metainfo for the torrent that includes the
 // info bytes and announce-list as currently known to the client.
 func (t *Torrent) Metainfo() metainfo.MetaInfo {
-       t.cl.lock()
-       defer t.cl.unlock()
+       t.cl.rLock()
+       defer t.cl.rUnlock()
        return t.newMetaInfo()
 }
 
@@ -153,32 +181,32 @@ func (t *Torrent) deleteReader(r *reader) {
 // has been obtained, see Torrent.Info and Torrent.GotInfo.
 func (t *Torrent) DownloadPieces(begin, end pieceIndex) {
        t.cl.lock()
-       defer t.cl.unlock()
        t.downloadPiecesLocked(begin, end)
+       t.cl.unlock()
 }
 
 func (t *Torrent) downloadPiecesLocked(begin, end pieceIndex) {
        for i := begin; i < end; i++ {
                if t.pieces[i].priority.Raise(PiecePriorityNormal) {
-                       t.updatePiecePriority(i)
+                       t.updatePiecePriority(i, "Torrent.DownloadPieces")
                }
        }
 }
 
 func (t *Torrent) CancelPieces(begin, end pieceIndex) {
        t.cl.lock()
-       defer t.cl.unlock()
-       t.cancelPiecesLocked(begin, end)
+       t.cancelPiecesLocked(begin, end, "Torrent.CancelPieces")
+       t.cl.unlock()
 }
 
-func (t *Torrent) cancelPiecesLocked(begin, end pieceIndex) {
+func (t *Torrent) cancelPiecesLocked(begin, end pieceIndex, reason string) {
        for i := begin; i < end; i++ {
                p := &t.pieces[i]
                if p.priority == PiecePriorityNone {
                        continue
                }
                p.priority = PiecePriorityNone
-               t.updatePiecePriority(i)
+               t.updatePiecePriority(i, reason)
        }
 }
 
@@ -188,15 +216,15 @@ func (t *Torrent) initFiles() {
        for _, fi := range t.info.UpvertedFiles() {
                *t.files = append(*t.files, &File{
                        t,
-                       strings.Join(append([]string{t.info.Name}, fi.Path...), "/"),
+                       strings.Join(append([]string{t.info.BestName()}, fi.BestPath()...), "/"),
                        offset,
                        fi.Length,
                        fi,
+                       fi.DisplayPath(t.info),
                        PiecePriorityNone,
                })
                offset += fi.Length
        }
-
 }
 
 // Returns handles to the files in the torrent. This requires that the Info is
@@ -205,11 +233,11 @@ func (t *Torrent) Files() []*File {
        return *t.files
 }
 
-func (t *Torrent) AddPeers(pp []Peer) {
-       cl := t.cl
-       cl.lock()
-       defer cl.unlock()
-       t.addPeers(pp)
+func (t *Torrent) AddPeers(pp []PeerInfo) (n int) {
+       t.cl.lock()
+       defer t.cl.unlock()
+       n = t.addPeers(pp)
+       return
 }
 
 // Marks the entire torrent for download. Requires the info first, see
@@ -221,9 +249,10 @@ func (t *Torrent) DownloadAll() {
 func (t *Torrent) String() string {
        s := t.name()
        if s == "" {
-               s = t.infoHash.HexString()
+               return t.infoHash.HexString()
+       } else {
+               return strconv.Quote(s)
        }
-       return s
 }
 
 func (t *Torrent) AddTrackers(announceList [][]string) {
@@ -233,7 +262,15 @@ func (t *Torrent) AddTrackers(announceList [][]string) {
 }
 
 func (t *Torrent) Piece(i pieceIndex) *Piece {
-       t.cl.lock()
-       defer t.cl.unlock()
-       return &t.pieces[i]
+       return t.piece(i)
+}
+
+func (t *Torrent) PeerConns() []*PeerConn {
+       t.cl.rLock()
+       defer t.cl.rUnlock()
+       ret := make([]*PeerConn, 0, len(t.conns))
+       for c := range t.conns {
+               ret = append(ret, c)
+       }
+       return ret
 }