]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/tracker-announce/main.go
511c783c35cedb2d9b928d23177a7fbe12191d12
[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         "github.com/anacrolix/torrent"
14         "github.com/anacrolix/torrent/metainfo"
15         "github.com/anacrolix/torrent/tracker"
16         "github.com/davecgh/go-spew/spew"
17 )
18
19 func argSpec(arg string) (ts *torrent.TorrentSpec, _ error) {
20         if strings.HasPrefix(arg, "magnet:") {
21                 return torrent.TorrentSpecFromMagnetUri(arg)
22         }
23         mi, fileErr := metainfo.LoadFromFile(arg)
24         if fileErr == nil {
25                 ts = torrent.TorrentSpecFromMetaInfo(mi)
26                 return
27         }
28         var ih torrent.InfoHash
29         ihErr := ih.FromHexString(arg)
30         if ihErr == nil {
31                 ts = &torrent.TorrentSpec{
32                         InfoHash: ih,
33                 }
34                 return
35         }
36         if len(arg) == 40 {
37                 return nil, ihErr
38         } else {
39                 return nil, fileErr
40         }
41 }
42
43 func main() {
44         flags := struct {
45                 Port    uint16
46                 Tracker []string
47                 tagflag.StartPos
48                 Torrents []string `arity:"+"`
49         }{
50                 Port: 50007,
51         }
52         tagflag.Parse(&flags)
53         var exitCode int32
54         var wg sync.WaitGroup
55         startAnnounce := func(ih torrent.InfoHash, tURI string) {
56                 ar := tracker.AnnounceRequest{
57                         NumWant:  -1,
58                         Left:     -1,
59                         Port:     flags.Port,
60                         InfoHash: ih,
61                 }
62                 wg.Add(1)
63                 go func(tURI string) {
64                         defer wg.Done()
65                         if doTracker(tURI, ar) {
66                                 atomic.StoreInt32(&exitCode, 1)
67                         }
68                 }(tURI)
69         }
70         for _, arg := range flags.Torrents {
71                 ts, err := argSpec(arg)
72                 if err != nil {
73                         log.Fatal(err)
74                 }
75                 for _, tier := range ts.Trackers {
76                         for _, tURI := range tier {
77                                 startAnnounce(ts.InfoHash, tURI)
78                         }
79                 }
80                 for _, tUri := range flags.Tracker {
81                         startAnnounce(ts.InfoHash, tUri)
82                 }
83         }
84         wg.Wait()
85         os.Exit(int(exitCode))
86 }
87
88 func doTracker(tURI string, ar tracker.AnnounceRequest) (hadError bool) {
89         for _, res := range announces(tURI, ar) {
90                 err := res.error
91                 resp := res.AnnounceResponse
92                 if err != nil {
93                         hadError = true
94                         log.Printf("error announcing to %q: %s", tURI, err)
95                         continue
96                 }
97                 fmt.Printf("from %q for %x:\n%s", tURI, ar.InfoHash, spew.Sdump(resp))
98         }
99         return
100 }
101
102 type announceResult struct {
103         tracker.AnnounceResponse
104         error
105 }
106
107 func announces(uri string, ar tracker.AnnounceRequest) (ret []announceResult) {
108         u, err := url.Parse(uri)
109         if err != nil {
110                 return []announceResult{{error: err}}
111         }
112         a := tracker.Announce{
113                 Request:    ar,
114                 TrackerUrl: uri,
115         }
116         if u.Scheme == "udp" {
117                 a.UdpNetwork = "udp4"
118                 ret = append(ret, announce(a))
119                 a.UdpNetwork = "udp6"
120                 ret = append(ret, announce(a))
121                 return
122         }
123         return []announceResult{announce(a)}
124 }
125
126 func announce(a tracker.Announce) announceResult {
127         resp, err := a.Do()
128         return announceResult{resp, err}
129 }