]> Sergey Matveev's repositories - btrtrc.git/blob - sources.go
Merge branch 'master' into crawshaw
[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 func (t *Torrent) useSources(sources []string) {
14         select {
15         case <-t.Closed():
16                 return
17         case <-t.GotInfo():
18                 return
19         default:
20         }
21         for _, s := range sources {
22                 _, loaded := t.activeSources.LoadOrStore(s, struct{}{})
23                 if loaded {
24                         continue
25                 }
26                 s := s
27                 go func() {
28                         err := t.useActiveTorrentSource(s)
29                         _, loaded := t.activeSources.LoadAndDelete(s)
30                         if !loaded {
31                                 panic(s)
32                         }
33                         level := log.Debug
34                         if err != nil {
35                                 level = log.Warning
36                         }
37                         t.logger.Levelf(level, "used torrent source %q [err=%v]", s, err)
38                 }()
39         }
40 }
41
42 func (t *Torrent) useActiveTorrentSource(source string) error {
43         ctx, cancel := context.WithCancel(context.Background())
44         defer cancel()
45         go func() {
46                 select {
47                 case <-t.GotInfo():
48                 case <-t.Closed():
49                 case <-ctx.Done():
50                 }
51                 cancel()
52         }()
53         mi, err := getTorrentSource(ctx, source, t.cl.httpClient)
54         if err != nil {
55                 return err
56         }
57         return t.MergeSpec(TorrentSpecFromMetaInfo(&mi))
58 }
59
60 func getTorrentSource(ctx context.Context, source string, hc *http.Client) (mi metainfo.MetaInfo, err error) {
61         var req *http.Request
62         if req, err = http.NewRequestWithContext(ctx, http.MethodGet, source, nil); err != nil {
63                 return
64         }
65         var resp *http.Response
66         if resp, err = hc.Do(req); err != nil {
67                 return
68         }
69         defer resp.Body.Close()
70         if resp.StatusCode != http.StatusOK {
71                 err = fmt.Errorf("unexpected response status code: %v", resp.StatusCode)
72                 return
73         }
74         err = bencode.NewDecoder(resp.Body).Decode(&mi)
75         return
76 }