1 // Downloads torrents from the command-line.
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"
21 "github.com/anacrolix/bargle"
22 "github.com/anacrolix/envpprof"
23 "github.com/anacrolix/log"
24 xprometheus "github.com/anacrolix/missinggo/v2/prometheus"
26 "github.com/anacrolix/torrent/bencode"
27 "github.com/anacrolix/torrent/version"
31 prometheus.MustRegister(xprometheus.NewExpvarCollector())
32 http.Handle("/metrics", promhttp.Handler())
35 func shutdownTracerProvider(ctx context.Context, tp *trace.TracerProvider) {
37 err := tp.Shutdown(ctx)
38 elapsed := time.Since(started)
39 log.Levelf(log.Error, "shutting down tracer provider (took %v): %v", elapsed, err)
43 defer stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
45 ctx := context.Background()
46 tracingExporter, err := otlptracegrpc.New(ctx)
48 log.Fatalf("creating tracing exporter: %v", err)
50 tracerProvider := trace.NewTracerProvider(trace.WithBatcher(tracingExporter))
51 defer shutdownTracerProvider(ctx, tracerProvider)
52 otel.SetTracerProvider(tracerProvider)
55 main.Defer(envpprof.Stop)
56 main.Defer(func() { shutdownTracerProvider(ctx, tracerProvider) })
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 {
65 cmd := bargle.FromStruct(&ac)
66 cmd.DefaultAction = func() error {
67 return announceErr(ac)
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)
80 bargle.Subcommand{Name: "download", Command: func() bargle.Command {
82 cmd := bargle.FromStruct(&dlc)
83 cmd.DefaultAction = func() error {
84 return downloadErr(downloadFlags{
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)
105 bargle.Subcommand{Name: "spew", Command: func() (cmd bargle.Command) {
106 cmd.DefaultAction = func() error {
107 config := spew.NewDefaultConfig()
108 config.DisableCapacities = true
110 print = func(v interface{}) error {
118 d := bencode.NewDecoder(os.Stdin)
119 cmd.AfterParseFunc = func(ctx bargle.Context) error {
120 ctx.AfterParse(func() error {
128 return fmt.Errorf("decoding message index %d: %w", i, err)
136 cmd.Desc = "reads bencoding from stdin into Go native types and spews the result"
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)
147 Desc: "prints various protocol default version strings",
149 bargle.Subcommand{Name: "serve", Command: serve()},
150 bargle.Subcommand{Name: "create", Command: create()},