]> Sergey Matveev's repositories - btrtrc.git/blob - sources.go
Export Torrent.UseSources
[btrtrc.git] / sources.go
1 package torrent
2
3 import (
4         "context"
5         "fmt"
6         "net/http"
7
8         "github.com/anacrolix/log"
9         "github.com/anacrolix/torrent/bencode"
10         "github.com/anacrolix/torrent/metainfo"
11 )
12
13 // Add HTTP endpoints that serve the metainfo. They will be used if the torrent info isn't obtained
14 // yet. The Client HTTP client is used.
15 func (t *Torrent) UseSources(sources []string) {
16         select {
17         case <-t.Closed():
18                 return
19         case <-t.GotInfo():
20                 return
21         default:
22         }
23         for _, s := range sources {
24                 _, loaded := t.activeSources.LoadOrStore(s, struct{}{})
25                 if loaded {
26                         continue
27                 }
28                 s := s
29                 go func() {
30                         err := t.useActiveTorrentSource(s)
31                         _, loaded := t.activeSources.LoadAndDelete(s)
32                         if !loaded {
33                                 panic(s)
34                         }
35                         level := log.Debug
36                         if err != nil {
37                                 level = log.Warning
38                         }
39                         t.logger.Levelf(level, "used torrent source %q [err=%v]", s, err)
40                 }()
41         }
42 }
43
44 func (t *Torrent) useActiveTorrentSource(source string) error {
45         ctx, cancel := context.WithCancel(context.Background())
46         defer cancel()
47         go func() {
48                 select {
49                 case <-t.GotInfo():
50                 case <-t.Closed():
51                 case <-ctx.Done():
52                 }
53                 cancel()
54         }()
55         mi, err := getTorrentSource(ctx, source, t.cl.httpClient)
56         if err != nil {
57                 return err
58         }
59         return t.MergeSpec(TorrentSpecFromMetaInfo(&mi))
60 }
61
62 func getTorrentSource(ctx context.Context, source string, hc *http.Client) (mi metainfo.MetaInfo, err error) {
63         var req *http.Request
64         if req, err = http.NewRequestWithContext(ctx, http.MethodGet, source, nil); err != nil {
65                 return
66         }
67         var resp *http.Response
68         if resp, err = hc.Do(req); err != nil {
69                 return
70         }
71         defer resp.Body.Close()
72         if resp.StatusCode != http.StatusOK {
73                 err = fmt.Errorf("unexpected response status code: %v", resp.StatusCode)
74                 return
75         }
76         err = bencode.NewDecoder(resp.Body).Decode(&mi)
77         return
78 }