]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/torrent/main.go
41003fd6037d8bdc3ba0977202cdbc984d14ceb8
[btrtrc.git] / cmd / torrent / main.go
1 // Downloads torrents from the command-line.
2 package main
3
4 import (
5         "encoding/json"
6         "errors"
7         "fmt"
8         "io"
9         stdLog "log"
10         "net/http"
11         "os"
12
13         "github.com/anacrolix/args"
14         "github.com/anacrolix/envpprof"
15         "github.com/anacrolix/log"
16         xprometheus "github.com/anacrolix/missinggo/v2/prometheus"
17         "github.com/anacrolix/torrent/bencode"
18         "github.com/anacrolix/torrent/version"
19         "github.com/davecgh/go-spew/spew"
20         "github.com/prometheus/client_golang/prometheus"
21         "github.com/prometheus/client_golang/prometheus/promhttp"
22 )
23
24 func main() {
25         if err := mainErr(); err != nil {
26                 log.Printf("error in main: %v", err)
27                 os.Exit(1)
28         }
29 }
30
31 func init() {
32         prometheus.MustRegister(xprometheus.NewExpvarCollector())
33         http.Handle("/metrics", promhttp.Handler())
34 }
35
36 func mainErr() error {
37         defer envpprof.Stop()
38         stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
39         debug := args.Flag(args.FlagOpt{Long: "debug"})
40         args.ParseMain(
41                 debug,
42                 args.Subcommand("metainfo", metainfoCmd),
43                 args.Subcommand("announce", func(p args.SubCmdCtx) error {
44                         var cmd AnnounceCmd
45                         err := p.NewParser().AddParams(
46                                 args.Pos("tracker", &cmd.Tracker),
47                                 args.Pos("infohash", &cmd.InfoHash)).Parse()
48                         if err != nil {
49                                 return err
50                         }
51                         return announceErr(cmd)
52                 }),
53                 args.Subcommand("scrape", func(p args.SubCmdCtx) error {
54                         var cmd ScrapeCmd
55                         err := p.NewParser().AddParams(
56                                 args.Pos("tracker", &cmd.Tracker),
57                                 args.Pos("infohash", &cmd.InfoHashes, args.Arity('+'))).Parse()
58                         if err != nil {
59                                 return err
60                         }
61                         return scrape(cmd)
62                 }),
63                 args.Subcommand("download", func(p args.SubCmdCtx) error {
64                         var dlc DownloadCmd
65                         err := p.NewParser().AddParams(
66                                 append(args.FromStruct(&dlc), debug)...,
67                         ).Parse()
68                         if err != nil {
69                                 return err
70                         }
71                         dlf := downloadFlags{
72                                 Debug:       debug.Bool(),
73                                 DownloadCmd: dlc,
74                         }
75                         p.Defer(func() error {
76                                 return downloadErr(dlf)
77                         })
78                         return nil
79                 }),
80                 args.Subcommand(
81                         "bencode",
82                         func(p args.SubCmdCtx) error {
83                                 var print func(interface{}) error
84                                 if !p.Parse(
85                                         args.Subcommand("json", func(ctx args.SubCmdCtx) (err error) {
86                                                 ctx.Parse()
87                                                 je := json.NewEncoder(os.Stdout)
88                                                 je.SetIndent("", "  ")
89                                                 print = je.Encode
90                                                 return nil
91                                         }),
92                                         args.Subcommand("spew", func(ctx args.SubCmdCtx) (err error) {
93                                                 ctx.Parse()
94                                                 config := spew.NewDefaultConfig()
95                                                 config.DisableCapacities = true
96                                                 config.Indent = "  "
97                                                 print = func(v interface{}) error {
98                                                         config.Dump(v)
99                                                         return nil
100                                                 }
101                                                 return nil
102                                         }),
103                                 ).RanSubCmd {
104                                         return errors.New("an output type is required")
105                                 }
106                                 d := bencode.NewDecoder(os.Stdin)
107                                 p.Defer(func() error {
108                                         for i := 0; ; i++ {
109                                                 var v interface{}
110                                                 err := d.Decode(&v)
111                                                 if err == io.EOF {
112                                                         break
113                                                 }
114                                                 if err != nil {
115                                                         return fmt.Errorf("decoding message index %d: %w", i, err)
116                                                 }
117                                                 print(v)
118                                         }
119                                         return nil
120                                 })
121                                 return nil
122                         },
123                         args.Help("reads bencoding from stdin into Go native types and spews the result"),
124                 ),
125                 args.Subcommand("version", func(p args.SubCmdCtx) error {
126                         fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
127                         fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
128                         fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
129                         return nil
130                 }),
131                 args.Subcommand("serve", serve, args.Help("creates and seeds a torrent from a filepath")),
132         )
133         return nil
134 }