]> Sergey Matveev's repositories - btrtrc.git/blob - cmd/torrent/main.go
Merge branch 'webrtc-conn-leak'
[btrtrc.git] / cmd / torrent / main.go
1 // Downloads torrents from the command-line.
2 package main
3
4 import (
5         "context"
6         "encoding/json"
7         "fmt"
8         "io"
9         stdLog "log"
10         "net/http"
11         "os"
12         "time"
13
14         "github.com/davecgh/go-spew/spew"
15         "github.com/prometheus/client_golang/prometheus"
16         "github.com/prometheus/client_golang/prometheus/promhttp"
17         "go.opentelemetry.io/otel"
18         "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
19         "go.opentelemetry.io/otel/sdk/trace"
20
21         "github.com/anacrolix/bargle"
22         "github.com/anacrolix/envpprof"
23         "github.com/anacrolix/log"
24         xprometheus "github.com/anacrolix/missinggo/v2/prometheus"
25
26         "github.com/anacrolix/torrent/bencode"
27         "github.com/anacrolix/torrent/version"
28 )
29
30 func init() {
31         prometheus.MustRegister(xprometheus.NewExpvarCollector())
32         http.Handle("/metrics", promhttp.Handler())
33 }
34
35 func shutdownTracerProvider(ctx context.Context, tp *trace.TracerProvider) {
36         started := time.Now()
37         err := tp.Shutdown(ctx)
38         elapsed := time.Since(started)
39         log.Levelf(log.Error, "shutting down tracer provider (took %v): %v", elapsed, err)
40 }
41
42 func main() {
43         defer stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
44
45         ctx := context.Background()
46         tracingExporter, err := otlptracegrpc.New(ctx)
47         if err != nil {
48                 log.Fatalf("creating tracing exporter: %v", err)
49         }
50         tracerProvider := trace.NewTracerProvider(trace.WithBatcher(tracingExporter))
51         defer shutdownTracerProvider(ctx, tracerProvider)
52         otel.SetTracerProvider(tracerProvider)
53
54         main := bargle.Main{}
55         main.Defer(envpprof.Stop)
56         main.Defer(func() { shutdownTracerProvider(ctx, tracerProvider) })
57         debug := false
58         debugFlag := bargle.NewFlag(&debug)
59         debugFlag.AddLong("debug")
60         main.Options = append(main.Options, debugFlag.Make())
61         main.Positionals = append(main.Positionals,
62                 bargle.Subcommand{Name: "metainfo", Command: metainfoCmd()},
63                 bargle.Subcommand{Name: "announce", Command: func() bargle.Command {
64                         var ac AnnounceCmd
65                         cmd := bargle.FromStruct(&ac)
66                         cmd.DefaultAction = func() error {
67                                 return announceErr(ac)
68                         }
69                         return cmd
70                 }()},
71                 bargle.Subcommand{Name: "scrape", Command: func() bargle.Command {
72                         var scrapeCfg scrapeCfg
73                         cmd := bargle.FromStruct(&scrapeCfg)
74                         cmd.Desc = "fetch swarm metrics for info-hashes from tracker"
75                         cmd.DefaultAction = func() error {
76                                 return scrape(scrapeCfg)
77                         }
78                         return cmd
79                 }()},
80                 bargle.Subcommand{Name: "download", Command: func() bargle.Command {
81                         var dlc DownloadCmd
82                         cmd := bargle.FromStruct(&dlc)
83                         cmd.DefaultAction = func() error {
84                                 return downloadErr(downloadFlags{
85                                         Debug:       debug,
86                                         DownloadCmd: dlc,
87                                 })
88                         }
89                         return cmd
90                 }()},
91                 bargle.Subcommand{
92                         Name: "bencode",
93                         Command: func() (cmd bargle.Command) {
94                                 var print func(interface{}) error
95                                 cmd.Positionals = append(cmd.Positionals,
96                                         bargle.Subcommand{Name: "json", Command: func() (cmd bargle.Command) {
97                                                 cmd.DefaultAction = func() error {
98                                                         je := json.NewEncoder(os.Stdout)
99                                                         je.SetIndent("", "  ")
100                                                         print = je.Encode
101                                                         return nil
102                                                 }
103                                                 return
104                                         }()},
105                                         bargle.Subcommand{Name: "spew", Command: func() (cmd bargle.Command) {
106                                                 cmd.DefaultAction = func() error {
107                                                         config := spew.NewDefaultConfig()
108                                                         config.DisableCapacities = true
109                                                         config.Indent = "  "
110                                                         print = func(v interface{}) error {
111                                                                 config.Dump(v)
112                                                                 return nil
113                                                         }
114                                                         return nil
115                                                 }
116                                                 return
117                                         }()})
118                                 d := bencode.NewDecoder(os.Stdin)
119                                 cmd.AfterParseFunc = func(ctx bargle.Context) error {
120                                         ctx.AfterParse(func() error {
121                                                 for i := 0; ; i++ {
122                                                         var v interface{}
123                                                         err := d.Decode(&v)
124                                                         if err == io.EOF {
125                                                                 break
126                                                         }
127                                                         if err != nil {
128                                                                 return fmt.Errorf("decoding message index %d: %w", i, err)
129                                                         }
130                                                         print(v)
131                                                 }
132                                                 return nil
133                                         })
134                                         return nil
135                                 }
136                                 cmd.Desc = "reads bencoding from stdin into Go native types and spews the result"
137                                 return
138                         }(),
139                 },
140                 bargle.Subcommand{Name: "version", Command: bargle.Command{
141                         DefaultAction: func() error {
142                                 fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
143                                 fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
144                                 fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
145                                 return nil
146                         },
147                         Desc: "prints various protocol default version strings",
148                 }},
149                 bargle.Subcommand{Name: "serve", Command: serve()},
150                 bargle.Subcommand{Name: "create", Command: create()},
151         )
152         main.Run()
153 }