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