github.com/anacrolix/torrent@v1.61.0/cmd/torrent/main.go (about) 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 "log/slog" 11 "net/http" 12 "os" 13 14 "github.com/anacrolix/bargle" 15 "github.com/anacrolix/envpprof" 16 app "github.com/anacrolix/gostdapp" 17 "github.com/anacrolix/log" 18 xprometheus "github.com/anacrolix/missinggo/v2/prometheus" 19 20 "github.com/davecgh/go-spew/spew" 21 "github.com/prometheus/client_golang/prometheus" 22 "github.com/prometheus/client_golang/prometheus/promhttp" 23 24 "github.com/anacrolix/torrent/bencode" 25 "github.com/anacrolix/torrent/version" 26 ) 27 28 func init() { 29 stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile) 30 prometheus.MustRegister(xprometheus.NewExpvarCollector()) 31 http.Handle("/metrics", promhttp.Handler()) 32 log.Default = log.NewLogger().WithDefaultLevel(log.Info) 33 log.Default.SetHandlers(log.SlogHandlerAsHandler{slog.Default().Handler()}) 34 } 35 36 func main() { 37 app.RunContext(mainErr) 38 } 39 40 func mainErr(ctx context.Context) error { 41 main := bargle.Main{} 42 main.Defer(envpprof.Stop) 43 debug := false 44 debugFlag := bargle.NewFlag(&debug) 45 debugFlag.AddLong("debug") 46 main.Options = append(main.Options, debugFlag.Make()) 47 main.AfterParseFunc = func(ctx bargle.Context) error { 48 if debug { 49 slog.SetLogLoggerLevel(slog.LevelDebug) 50 } 51 return nil 52 } 53 main.Positionals = append(main.Positionals, 54 bargle.Subcommand{Name: "metainfo", Command: metainfoCmd()}, 55 bargle.Subcommand{Name: "announce", Command: func() bargle.Command { 56 var ac AnnounceCmd 57 cmd := bargle.FromStruct(&ac) 58 cmd.DefaultAction = func() error { 59 return announceErr(ac) 60 } 61 return cmd 62 }()}, 63 bargle.Subcommand{Name: "scrape", Command: func() bargle.Command { 64 var scrapeCfg scrapeCfg 65 cmd := bargle.FromStruct(&scrapeCfg) 66 cmd.Desc = "fetch swarm metrics for info-hashes from tracker" 67 cmd.DefaultAction = func() error { 68 return scrape(scrapeCfg) 69 } 70 return cmd 71 }()}, 72 bargle.Subcommand{Name: "download", Command: func() bargle.Command { 73 var dlc DownloadCmd 74 cmd := bargle.FromStruct(&dlc) 75 cmd.DefaultAction = func() error { 76 return downloadErr( 77 ctx, 78 downloadFlags{ 79 Debug: debug, 80 DownloadCmd: dlc, 81 }, 82 slog.Default(), 83 ) 84 } 85 return cmd 86 }()}, 87 bargle.Subcommand{ 88 Name: "bencode", 89 Command: func() (cmd bargle.Command) { 90 var print func(interface{}) error 91 cmd.Positionals = append(cmd.Positionals, 92 bargle.Subcommand{Name: "json", Command: func() (cmd bargle.Command) { 93 cmd.DefaultAction = func() error { 94 je := json.NewEncoder(os.Stdout) 95 je.SetIndent("", " ") 96 print = je.Encode 97 return nil 98 } 99 return 100 }()}, 101 bargle.Subcommand{Name: "spew", Command: func() (cmd bargle.Command) { 102 cmd.DefaultAction = func() error { 103 config := spew.NewDefaultConfig() 104 config.DisableCapacities = true 105 config.Indent = " " 106 print = func(v interface{}) error { 107 config.Dump(v) 108 return nil 109 } 110 return nil 111 } 112 return 113 }()}) 114 d := bencode.NewDecoder(os.Stdin) 115 cmd.AfterParseFunc = func(ctx bargle.Context) error { 116 ctx.AfterParse(func() error { 117 for i := 0; ; i++ { 118 var v interface{} 119 err := d.Decode(&v) 120 if err == io.EOF { 121 break 122 } 123 if err != nil { 124 return fmt.Errorf("decoding message index %d: %w", i, err) 125 } 126 print(v) 127 } 128 return nil 129 }) 130 return nil 131 } 132 cmd.Desc = "reads bencoding from stdin into Go native types and spews the result" 133 return 134 }(), 135 }, 136 bargle.Subcommand{Name: "version", Command: bargle.Command{ 137 DefaultAction: func() error { 138 fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent) 139 fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion) 140 fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix) 141 return nil 142 }, 143 Desc: "prints various protocol default version strings", 144 }}, 145 bargle.Subcommand{Name: "serve", Command: serve()}, 146 bargle.Subcommand{Name: "create", Command: create()}, 147 ) 148 // Well this sux, this old version of bargle doesn't return so we can let the gostdapp Context 149 // clean up. 150 main.Run() 151 return nil 152 }