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