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"
19 func argSpec(arg string) (ts *torrent.TorrentSpec, _ error) {
20 if strings.HasPrefix(arg, "magnet:") {
21 return torrent.TorrentSpecFromMagnetUri(arg)
23 mi, fileErr := metainfo.LoadFromFile(arg)
25 ts = torrent.TorrentSpecFromMetaInfo(mi)
28 var ih torrent.InfoHash
29 ihErr := ih.FromHexString(arg)
31 ts = &torrent.TorrentSpec{
48 Torrents []string `arity:"+"`
55 startAnnounce := func(ih torrent.InfoHash, tURI string) {
56 ar := tracker.AnnounceRequest{
63 go func(tURI string) {
65 if doTracker(tURI, ar) {
66 atomic.StoreInt32(&exitCode, 1)
70 for _, arg := range flags.Torrents {
71 ts, err := argSpec(arg)
75 for _, tier := range ts.Trackers {
76 for _, tURI := range tier {
77 startAnnounce(ts.InfoHash, tURI)
80 for _, tUri := range flags.Tracker {
81 startAnnounce(ts.InfoHash, tUri)
85 os.Exit(int(exitCode))
88 func doTracker(tURI string, ar tracker.AnnounceRequest) (hadError bool) {
89 for _, res := range announces(tURI, ar) {
91 resp := res.AnnounceResponse
94 log.Printf("error announcing to %q: %s", tURI, err)
97 fmt.Printf("from %q for %x:\n%s", tURI, ar.InfoHash, spew.Sdump(resp))
102 type announceResult struct {
103 tracker.AnnounceResponse
107 func announces(uri string, ar tracker.AnnounceRequest) (ret []announceResult) {
108 u, err := url.Parse(uri)
110 return []announceResult{{error: err}}
112 a := tracker.Announce{
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))
123 return []announceResult{announce(a)}
126 func announce(a tracker.Announce) announceResult {
128 return announceResult{resp, err}