X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=t.go;h=45856cc7acbeaa5988074f74435d078a49111a57;hb=HEAD;hp=cd8bc10cd88b9e9be2bcad880756005fdf515af4;hpb=499b2d8725f44506a0172a0952e6313769833efd;p=btrtrc.git diff --git a/t.go b/t.go index cd8bc10c..45856cc7 100644 --- a/t.go +++ b/t.go @@ -4,57 +4,78 @@ 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 { +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 +} + +// 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() - defer t.cl.rUnlock() - return t.pieceStateRuns() + runs = t.pieceStateRuns() + t.cl.rUnlock() + return } -func (t *Torrent) PieceState(piece pieceIndex) PieceState { +func (t *Torrent) PieceState(piece pieceIndex) (ps PieceState) { t.cl.rLock() - defer t.cl.rUnlock() - return t.pieceState(piece) + ps = t.pieceState(piece) + t.cl.rUnlock() + return } // The number of pieces in the torrent. This requires that the info has been @@ -65,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()) } @@ -75,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 @@ -92,27 +118,27 @@ 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.nameMu.Lock() - defer t.nameMu.Unlock() - if t.haveInfo() { - return + if !t.haveInfo() { + t.displayName = dn } - t.displayName = dn + t.nameMu.Unlock() } // The current working name for the torrent. Either the name in the info dict, @@ -124,14 +150,14 @@ func (t *Torrent) Name() string { // 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() } @@ -155,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) } } @@ -190,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 @@ -207,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 @@ -236,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 }