]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/tracker-announce/main.go
8d9681dd4f94c75bdc9defd8059bc8a4814d4d01
[btrtrc.git] / cmd / tracker-announce / main.go
1 package main
2
3 import (
4         "fmt"
5         "log"
6         "net/url"
7         "os"
8         "strings"
9         "sync"
10         "sync/atomic"
11
12         "github.com/anacrolix/tagflag"
13
14         "github.com/anacrolix/torrent"
15         "github.com/anacrolix/torrent/metainfo"
16         "github.com/anacrolix/torrent/tracker"
17 )
18
19 func argSpec(arg string) (ts *torrent.TorrentSpec, err error) {
20         if strings.HasPrefix(arg, "magnet:") {
21                 return torrent.TorrentSpecFromMagnetURI(arg)
22         }
23         mi, err := metainfo.LoadFromFile(arg)
24         if err != nil {
25                 return
26         }
27         ts = torrent.TorrentSpecFromMetaInfo(mi)
28         return
29 }
30
31 func main() {
32         flags := struct {
33                 Port uint16
34                 tagflag.StartPos
35                 Torrents []string `arity:"+"`
36         }{
37                 Port: 50007,
38         }
39         tagflag.Parse(&flags)
40         var exitCode int32
41         var wg sync.WaitGroup
42         for _, arg := range flags.Torrents {
43                 ts, err := argSpec(arg)
44                 if err != nil {
45                         log.Fatal(err)
46                 }
47                 for _, tier := range ts.Trackers {
48                         for _, tURI := range tier {
49                                 ar := tracker.AnnounceRequest{
50                                         NumWant:  -1,
51                                         Left:     -1,
52                                         Port:     flags.Port,
53                                         InfoHash: ts.InfoHash,
54                                 }
55                                 wg.Add(1)
56                                 go func(tURI string) {
57                                         defer wg.Done()
58                                         if doTracker(tURI, ar) {
59                                                 atomic.StoreInt32(&exitCode, 1)
60                                         }
61                                 }(tURI)
62                         }
63                 }
64         }
65         wg.Wait()
66         os.Exit(int(exitCode))
67 }
68
69 func doTracker(tURI string, ar tracker.AnnounceRequest) (hadError bool) {
70         for _, res := range announces(tURI, ar) {
71                 err := res.error
72                 resp := res.AnnounceResponse
73                 if err != nil {
74                         hadError = true
75                         log.Printf("error announcing to %q: %s", tURI, err)
76                         continue
77                 }
78                 fmt.Printf("response from %q: %+v\n", tURI, resp)
79         }
80         return
81 }
82
83 type announceResult struct {
84         tracker.AnnounceResponse
85         error
86 }
87
88 func announces(uri string, ar tracker.AnnounceRequest) (ret []announceResult) {
89         u, err := url.Parse(uri)
90         if err != nil {
91                 return []announceResult{{error: err}}
92         }
93         a := tracker.Announce{
94                 Request:    ar,
95                 TrackerUrl: uri,
96         }
97         if u.Scheme == "udp" {
98                 a.UdpNetwork = "udp4"
99                 ret = append(ret, announce(a))
100                 a.UdpNetwork = "udp6"
101                 ret = append(ret, announce(a))
102                 return
103         }
104         return []announceResult{announce(a)}
105 }
106
107 func announce(a tracker.Announce) announceResult {
108         resp, err := a.Do()
109         return announceResult{resp, err}
110 }