t.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package torrent
  2. import (
  3. "strconv"
  4. "strings"
  5. "github.com/anacrolix/chansync/events"
  6. "github.com/anacrolix/missinggo/v2/pubsub"
  7. "github.com/anacrolix/sync"
  8. "github.com/anacrolix/torrent/metainfo"
  9. )
  10. // The Torrent's infohash. This is fixed and cannot change. It uniquely identifies a torrent.
  11. func (t *Torrent) InfoHash() metainfo.Hash {
  12. return *t.canonicalShortInfohash()
  13. }
  14. // Returns a channel that is closed when the info (.Info()) for the torrent has become available.
  15. func (t *Torrent) GotInfo() events.Done {
  16. return t.gotMetainfoC
  17. }
  18. // Returns the metainfo info dictionary, or nil if it's not yet available.
  19. func (t *Torrent) Info() (info *metainfo.Info) {
  20. t.nameMu.RLock()
  21. info = t.info
  22. t.nameMu.RUnlock()
  23. return
  24. }
  25. // Returns a Reader bound to the torrent's data. All read calls block until the data requested is
  26. // actually available. Note that you probably want to ensure the Torrent Info is available first.
  27. func (t *Torrent) NewReader() Reader {
  28. return t.newReader(0, t.length())
  29. }
  30. func (t *Torrent) newReader(offset, length int64) Reader {
  31. r := reader{
  32. mu: t.cl.locker(),
  33. t: t,
  34. offset: offset,
  35. length: length,
  36. }
  37. r.readaheadFunc = defaultReadaheadFunc
  38. t.addReader(&r)
  39. return &r
  40. }
  41. type PieceStateRuns []PieceStateRun
  42. func (me PieceStateRuns) String() (s string) {
  43. if len(me) > 0 {
  44. var sb strings.Builder
  45. sb.WriteString(me[0].String())
  46. for i := 1; i < len(me); i += 1 {
  47. sb.WriteByte(' ')
  48. sb.WriteString(me[i].String())
  49. }
  50. return sb.String()
  51. }
  52. return
  53. }
  54. // Returns the state of pieces of the torrent. They are grouped into runs of same state. The sum of
  55. // the state run-lengths is the number of pieces in the torrent.
  56. func (t *Torrent) PieceStateRuns() (runs PieceStateRuns) {
  57. t.cl.rLock()
  58. runs = t.pieceStateRuns()
  59. t.cl.rUnlock()
  60. return
  61. }
  62. func (t *Torrent) PieceState(piece pieceIndex) (ps PieceState) {
  63. t.cl.rLock()
  64. ps = t.pieceState(piece)
  65. t.cl.rUnlock()
  66. return
  67. }
  68. // The number of pieces in the torrent. This requires that the info has been
  69. // obtained first.
  70. func (t *Torrent) NumPieces() pieceIndex {
  71. return t.numPieces()
  72. }
  73. // Get missing bytes count for specific piece.
  74. func (t *Torrent) PieceBytesMissing(piece int) int64 {
  75. t.cl.rLock()
  76. defer t.cl.rUnlock()
  77. return int64(t.pieces[piece].bytesLeft())
  78. }
  79. // Drop the torrent from the client, and close it. It's always safe to do
  80. // this. No data corruption can, or should occur to either the torrent's data,
  81. // or connected peers.
  82. func (t *Torrent) Drop() {
  83. var wg sync.WaitGroup
  84. defer wg.Wait()
  85. t.cl.lock()
  86. defer t.cl.unlock()
  87. err := t.cl.dropTorrent(t, &wg)
  88. if err != nil {
  89. panic(err)
  90. }
  91. }
  92. // Number of bytes of the entire torrent we have completed. This is the sum of
  93. // completed pieces, and dirtied chunks of incomplete pieces. Do not use this
  94. // for download rate, as it can go down when pieces are lost or fail checks.
  95. // Sample Torrent.Stats.DataBytesRead for actual file data download rate.
  96. func (t *Torrent) BytesCompleted() int64 {
  97. t.cl.rLock()
  98. defer t.cl.rUnlock()
  99. return t.bytesCompleted()
  100. }
  101. // The subscription emits as (int) the index of pieces as their state changes.
  102. // A state change is when the PieceState for a piece alters in value.
  103. func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription[PieceStateChange] {
  104. return t.pieceStateChanges.Subscribe()
  105. }
  106. // Returns true if the torrent is currently being seeded. This occurs when the
  107. // client is willing to upload without wanting anything in return.
  108. func (t *Torrent) Seeding() (ret bool) {
  109. t.cl.rLock()
  110. ret = t.seeding()
  111. t.cl.rUnlock()
  112. return
  113. }
  114. // Clobbers the torrent display name if metainfo is unavailable.
  115. // The display name is used as the torrent name while the metainfo is unavailable.
  116. func (t *Torrent) SetDisplayName(dn string) {
  117. t.nameMu.Lock()
  118. if !t.haveInfo() {
  119. t.displayName = dn
  120. }
  121. t.nameMu.Unlock()
  122. }
  123. // The current working name for the torrent. Either the name in the info dict,
  124. // or a display name given such as by the dn value in a magnet link, or "".
  125. func (t *Torrent) Name() string {
  126. return t.name()
  127. }
  128. // The completed length of all the torrent data, in all its files. This is
  129. // derived from the torrent info, when it is available.
  130. func (t *Torrent) Length() int64 {
  131. return t._length.Value
  132. }
  133. // Returns a run-time generated metainfo for the torrent that includes the
  134. // info bytes and announce-list as currently known to the client.
  135. func (t *Torrent) Metainfo() metainfo.MetaInfo {
  136. t.cl.rLock()
  137. defer t.cl.rUnlock()
  138. return t.newMetaInfo()
  139. }
  140. func (t *Torrent) addReader(r *reader) {
  141. t.cl.lock()
  142. defer t.cl.unlock()
  143. if t.readers == nil {
  144. t.readers = make(map[*reader]struct{})
  145. }
  146. t.readers[r] = struct{}{}
  147. r.posChanged()
  148. }
  149. func (t *Torrent) deleteReader(r *reader) {
  150. delete(t.readers, r)
  151. t.readersChanged()
  152. }
  153. // Raise the priorities of pieces in the range [begin, end) to at least Normal
  154. // priority. Piece indexes are not the same as bytes. Requires that the info
  155. // has been obtained, see Torrent.Info and Torrent.GotInfo.
  156. func (t *Torrent) DownloadPieces(begin, end pieceIndex) {
  157. t.cl.lock()
  158. t.downloadPiecesLocked(begin, end)
  159. t.cl.unlock()
  160. }
  161. func (t *Torrent) downloadPiecesLocked(begin, end pieceIndex) {
  162. for i := begin; i < end; i++ {
  163. if t.pieces[i].priority.Raise(PiecePriorityNormal) {
  164. t.updatePiecePriority(i, "Torrent.DownloadPieces")
  165. }
  166. }
  167. }
  168. func (t *Torrent) CancelPieces(begin, end pieceIndex) {
  169. t.cl.lock()
  170. t.cancelPiecesLocked(begin, end, "Torrent.CancelPieces")
  171. t.cl.unlock()
  172. }
  173. func (t *Torrent) cancelPiecesLocked(begin, end pieceIndex, reason updateRequestReason) {
  174. for i := begin; i < end; i++ {
  175. p := &t.pieces[i]
  176. if p.priority == PiecePriorityNone {
  177. continue
  178. }
  179. p.priority = PiecePriorityNone
  180. t.updatePiecePriority(i, reason)
  181. }
  182. }
  183. func (t *Torrent) initFiles() {
  184. info := t.info
  185. var offset int64
  186. t.files = new([]*File)
  187. for _, fi := range t.info.UpvertedFiles() {
  188. *t.files = append(*t.files, &File{
  189. t,
  190. strings.Join(append([]string{info.BestName()}, fi.BestPath()...), "/"),
  191. offset,
  192. fi.Length,
  193. fi,
  194. fi.DisplayPath(info),
  195. PiecePriorityNone,
  196. fi.PiecesRoot,
  197. })
  198. offset += fi.Length
  199. if info.FilesArePieceAligned() {
  200. offset = (offset + info.PieceLength - 1) / info.PieceLength * info.PieceLength
  201. }
  202. }
  203. }
  204. // Returns handles to the files in the torrent. This requires that the Info is
  205. // available first.
  206. func (t *Torrent) Files() []*File {
  207. return *t.files
  208. }
  209. func (t *Torrent) AddPeers(pp []PeerInfo) (n int) {
  210. t.cl.lock()
  211. defer t.cl.unlock()
  212. n = t.addPeers(pp)
  213. return
  214. }
  215. // Marks the entire torrent for download. Requires the info first, see
  216. // GotInfo. Sets piece priorities for historical reasons.
  217. func (t *Torrent) DownloadAll() {
  218. t.DownloadPieces(0, t.numPieces())
  219. }
  220. func (t *Torrent) String() string {
  221. s := t.name()
  222. if s == "" {
  223. return t.canonicalShortInfohash().HexString()
  224. } else {
  225. return strconv.Quote(s)
  226. }
  227. }
  228. func (t *Torrent) AddTrackers(announceList [][]string) {
  229. t.cl.lock()
  230. defer t.cl.unlock()
  231. t.addTrackers(announceList)
  232. }
  233. func (t *Torrent) ModifyTrackers(announceList [][]string) {
  234. t.cl.lock()
  235. defer t.cl.unlock()
  236. t.modifyTrackers(announceList)
  237. }
  238. func (t *Torrent) Piece(i pieceIndex) *Piece {
  239. return t.piece(i)
  240. }
  241. func (t *Torrent) PeerConns() []*PeerConn {
  242. t.cl.rLock()
  243. defer t.cl.rUnlock()
  244. ret := make([]*PeerConn, 0, len(t.conns))
  245. for c := range t.conns {
  246. ret = append(ret, c)
  247. }
  248. return ret
  249. }
  250. func (t *Torrent) WebseedPeerConns() []*Peer {
  251. t.cl.rLock()
  252. defer t.cl.rUnlock()
  253. ret := make([]*Peer, 0, len(t.conns))
  254. for _, c := range t.webSeeds {
  255. ret = append(ret, c)
  256. }
  257. return ret
  258. }