]> Sergey Matveev's repositories - btrtrc.git/blob - t.go
Move a bunch of Torrent methods from client.go
[btrtrc.git] / t.go
1 package torrent
2
3 import (
4         "fmt"
5         "strings"
6
7         "github.com/anacrolix/missinggo/pubsub"
8
9         "github.com/anacrolix/torrent/metainfo"
10 )
11
12 // The torrent's infohash. This is fixed and cannot change. It uniquely
13 // identifies a torrent.
14 func (t *Torrent) InfoHash() metainfo.Hash {
15         return t.infoHash
16 }
17
18 // Returns a channel that is closed when the info (.Info()) for the torrent
19 // has become available.
20 func (t *Torrent) GotInfo() <-chan struct{} {
21         return t.gotMetainfo
22 }
23
24 // Returns the metainfo info dictionary, or nil if it's not yet available.
25 func (t *Torrent) Info() *metainfo.InfoEx {
26         return t.info
27 }
28
29 // Returns a Reader bound to the torrent's data. All read calls block until
30 // the data requested is actually available.
31 func (t *Torrent) NewReader() (ret *Reader) {
32         ret = &Reader{
33                 t:         t,
34                 readahead: 5 * 1024 * 1024,
35         }
36         t.addReader(ret)
37         return
38 }
39
40 // Returns the state of pieces of the torrent. They are grouped into runs of
41 // same state. The sum of the state run lengths is the number of pieces
42 // in the torrent.
43 func (t *Torrent) PieceStateRuns() []PieceStateRun {
44         t.cl.mu.Lock()
45         defer t.cl.mu.Unlock()
46         return t.pieceStateRuns()
47 }
48
49 func (t *Torrent) PieceState(piece int) PieceState {
50         t.cl.mu.Lock()
51         defer t.cl.mu.Unlock()
52         return t.pieceState(piece)
53 }
54
55 // The number of pieces in the torrent. This requires that the info has been
56 // obtained first.
57 func (t *Torrent) NumPieces() int {
58         return t.numPieces()
59 }
60
61 // Drop the torrent from the client, and close it. It's always safe to do
62 // this. No data corruption can, or should occur to either the torrent's data,
63 // or connected peers.
64 func (t *Torrent) Drop() {
65         t.cl.mu.Lock()
66         t.cl.dropTorrent(t.infoHash)
67         t.cl.mu.Unlock()
68 }
69
70 // Number of bytes of the entire torrent we have completed.
71 func (t *Torrent) BytesCompleted() int64 {
72         t.cl.mu.RLock()
73         defer t.cl.mu.RUnlock()
74         return t.bytesCompleted()
75 }
76
77 // The subscription emits as (int) the index of pieces as their state changes.
78 // A state change is when the PieceState for a piece alters in value.
79 func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription {
80         return t.pieceStateChanges.Subscribe()
81 }
82
83 // Returns true if the torrent is currently being seeded. This occurs when the
84 // client is willing to upload without wanting anything in return.
85 func (t *Torrent) Seeding() bool {
86         t.cl.mu.Lock()
87         defer t.cl.mu.Unlock()
88         return t.cl.seeding(t)
89 }
90
91 // Clobbers the torrent display name. The display name is used as the torrent
92 // name if the metainfo is not available.
93 func (t *Torrent) SetDisplayName(dn string) {
94         t.cl.mu.Lock()
95         defer t.cl.mu.Unlock()
96         t.setDisplayName(dn)
97 }
98
99 // The current working name for the torrent. Either the name in the info dict,
100 // or a display name given such as by the dn value in a magnet link, or "".
101 func (t *Torrent) Name() string {
102         t.cl.mu.Lock()
103         defer t.cl.mu.Unlock()
104         return t.name()
105 }
106
107 // The completed length of all the torrent data, in all its files. This is
108 // derived from the torrent info, when it is available.
109 func (t *Torrent) Length() int64 {
110         if t.info == nil {
111                 panic("not valid until info obtained")
112         }
113         return t.length
114 }
115
116 // Returns a run-time generated metainfo for the torrent that includes the
117 // info bytes and announce-list as currently known to the client.
118 func (t *Torrent) Metainfo() *metainfo.MetaInfo {
119         t.cl.mu.Lock()
120         defer t.cl.mu.Unlock()
121         return t.metainfo()
122 }
123
124 func (t *Torrent) addReader(r *Reader) {
125         t.cl.mu.Lock()
126         defer t.cl.mu.Unlock()
127         if t.readers == nil {
128                 t.readers = make(map[*Reader]struct{})
129         }
130         t.readers[r] = struct{}{}
131         t.readersChanged()
132 }
133
134 func (t *Torrent) deleteReader(r *Reader) {
135         t.cl.mu.Lock()
136         defer t.cl.mu.Unlock()
137         delete(t.readers, r)
138         t.readersChanged()
139 }
140
141 func (t *Torrent) DownloadPieces(begin, end int) {
142         t.cl.mu.Lock()
143         defer t.cl.mu.Unlock()
144         t.pendPieceRange(begin, end)
145 }
146
147 func (t *Torrent) CancelPieces(begin, end int) {
148         t.cl.mu.Lock()
149         defer t.cl.mu.Unlock()
150         t.unpendPieceRange(begin, end)
151 }
152
153 // Returns handles to the files in the torrent. This requires the metainfo is
154 // available first.
155 func (t *Torrent) Files() (ret []File) {
156         t.cl.mu.Lock()
157         info := t.Info()
158         t.cl.mu.Unlock()
159         if info == nil {
160                 return
161         }
162         var offset int64
163         for _, fi := range info.UpvertedFiles() {
164                 ret = append(ret, File{
165                         t,
166                         strings.Join(append([]string{info.Name}, fi.Path...), "/"),
167                         offset,
168                         fi.Length,
169                         fi,
170                 })
171                 offset += fi.Length
172         }
173         return
174 }
175
176 func (t *Torrent) AddPeers(pp []Peer) error {
177         cl := t.cl
178         cl.mu.Lock()
179         defer cl.mu.Unlock()
180         cl.addPeers(t, pp)
181         return nil
182 }
183
184 // Marks the entire torrent for download. Requires the info first, see
185 // GotInfo.
186 func (t *Torrent) DownloadAll() {
187         t.cl.mu.Lock()
188         defer t.cl.mu.Unlock()
189         t.pendPieceRange(0, t.numPieces())
190 }
191
192 func (t *Torrent) String() string {
193         s := t.name()
194         if s == "" {
195                 s = fmt.Sprintf("%x", t.infoHash)
196         }
197         return s
198 }