package main
import (
- "encoding/json"
- "errors"
- "fmt"
- "io"
stdLog "log"
"net/http"
- "os"
- "github.com/anacrolix/args"
+ "github.com/anacrolix/bargle"
"github.com/anacrolix/envpprof"
- "github.com/anacrolix/log"
xprometheus "github.com/anacrolix/missinggo/v2/prometheus"
- "github.com/anacrolix/torrent/bencode"
- "github.com/anacrolix/torrent/version"
- "github.com/davecgh/go-spew/spew"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
-func main() {
- if err := mainErr(); err != nil {
- log.Printf("error in main: %v", err)
- os.Exit(1)
- }
-}
-
func init() {
prometheus.MustRegister(xprometheus.NewExpvarCollector())
http.Handle("/metrics", promhttp.Handler())
}
-func mainErr() error {
- defer envpprof.Stop()
- stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
- debug := args.Flag(args.FlagOpt{Long: "debug"})
- return args.ParseMain(
- debug,
- args.Subcommand("metainfo", metainfoCmd),
- args.Subcommand("announce", func(p args.SubCmdCtx) error {
- var cmd AnnounceCmd
- err := p.NewParser().AddParams(
- args.Pos("tracker", &cmd.Tracker),
- args.Pos("infohash", &cmd.InfoHash)).Parse()
- if err != nil {
- return err
- }
- return announceErr(cmd)
- }),
- args.Subcommand("scrape", func(p args.SubCmdCtx) error {
- var cmd ScrapeCmd
- err := p.NewParser().AddParams(
- args.Pos("tracker", &cmd.Tracker),
- args.Pos("infohash", &cmd.InfoHashes, args.Arity('+'))).Parse()
- if err != nil {
- return err
- }
- return scrape(cmd)
- }),
- args.Subcommand("download", func(p args.SubCmdCtx) error {
+func main() {
+ defer stdLog.SetFlags(stdLog.Flags() | stdLog.Lshortfile)
+ main := bargle.Main{}
+ main.Defer(envpprof.Stop)
+ debug := false
+ main.Options = append(main.Options, bargle.Flag{Longs: []string{"debug"}, Value: &debug})
+ main.Positionals = append(main.Positionals,
+ bargle.Subcommand{Name: "metainfo", Command: metainfoCmd()},
+ //bargle.Subcommand{Name: "announce", Command: func() bargle.Command {
+ // var cmd AnnounceCmd
+ // err := p.NewParser().AddParams(
+ // args.Pos("tracker", &cmd.Tracker),
+ // args.Pos("infohash", &cmd.InfoHash)).Parse()
+ // if err != nil {
+ // return err
+ // }
+ // return announceErr(cmd)
+ //}()},
+ //bargle.Subcommand{Name: "scrape", Command: func() bargle.Command {
+ // var cmd ScrapeCmd
+ // err := p.NewParser().AddParams(
+ // args.Pos("tracker", &cmd.Tracker),
+ // args.Pos("infohash", &cmd.InfoHashes, args.Arity('+'))).Parse()
+ // if err != nil {
+ // return err
+ // }
+ // return scrape(cmd)
+ //}()},
+ bargle.Subcommand{Name: "download", Command: func() bargle.Command {
var dlc DownloadCmd
- err := p.NewParser().AddParams(
- append(args.FromStruct(&dlc), debug)...,
- ).Parse()
- if err != nil {
- return err
- }
- dlf := downloadFlags{
- Debug: debug.Bool(),
- DownloadCmd: dlc,
- }
- p.Defer(func() error {
- return downloadErr(dlf)
- })
- return nil
- }),
- args.Subcommand(
- "bencode",
- func(p args.SubCmdCtx) error {
- var print func(interface{}) error
- if !p.Parse(
- args.Subcommand("json", func(ctx args.SubCmdCtx) (err error) {
- ctx.Parse()
- je := json.NewEncoder(os.Stdout)
- je.SetIndent("", " ")
- print = je.Encode
- return nil
- }),
- args.Subcommand("spew", func(ctx args.SubCmdCtx) (err error) {
- ctx.Parse()
- config := spew.NewDefaultConfig()
- config.DisableCapacities = true
- config.Indent = " "
- print = func(v interface{}) error {
- config.Dump(v)
- return nil
- }
- return nil
- }),
- ).RanSubCmd {
- return errors.New("an output type is required")
- }
- d := bencode.NewDecoder(os.Stdin)
- p.Defer(func() error {
- for i := 0; ; i++ {
- var v interface{}
- err := d.Decode(&v)
- if err == io.EOF {
- break
- }
- if err != nil {
- return fmt.Errorf("decoding message index %d: %w", i, err)
- }
- print(v)
- }
- return nil
+ cmd := bargle.FromStruct(&dlc)
+ cmd.DefaultAction = func() error {
+ return downloadErr(downloadFlags{
+ Debug: debug,
+ DownloadCmd: dlc,
})
- return nil
- },
- args.Help("reads bencoding from stdin into Go native types and spews the result"),
- ),
- args.Subcommand("version", func(p args.SubCmdCtx) error {
- fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
- fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
- fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
- return nil
- }),
- args.Subcommand("serve", serve, args.Help("creates and seeds a torrent from a filepath")),
+ }
+ return cmd
+ }()},
+ //bargle.Subcommand{Name:
+ // "bencode", Command: func() bargle.Command {
+ // var print func(interface{}) error
+ // if !p.Parse(
+ // args.Subcommand("json", func(ctx args.SubCmdCtx) (err error) {
+ // ctx.Parse()
+ // je := json.NewEncoder(os.Stdout)
+ // je.SetIndent("", " ")
+ // print = je.Encode
+ // return nil
+ // }),
+ // args.Subcommand("spew", func(ctx args.SubCmdCtx) (err error) {
+ // ctx.Parse()
+ // config := spew.NewDefaultConfig()
+ // config.DisableCapacities = true
+ // config.Indent = " "
+ // print = func(v interface{}) error {
+ // config.Dump(v)
+ // return nil
+ // }
+ // return nil
+ // }),
+ // ).RanSubCmd {
+ // return errors.New("an output type is required")
+ // }
+ // d := bencode.NewDecoder(os.Stdin)
+ // p.Defer(func() error {
+ // for i := 0; ; i++ {
+ // var v interface{}
+ // err := d.Decode(&v)
+ // if err == io.EOF {
+ // break
+ // }
+ // if err != nil {
+ // return fmt.Errorf("decoding message index %d: %w", i, err)
+ // }
+ // print(v)
+ // }
+ // return nil
+ // })
+ // return nil
+ // }(),
+ // Desc: "reads bencoding from stdin into Go native types and spews the result",
+ //},
+ //bargle.Subcommand{Name: "version", Command: func() bargle.Command {
+ // fmt.Printf("HTTP User-Agent: %q\n", version.DefaultHttpUserAgent)
+ // fmt.Printf("Torrent client version: %q\n", version.DefaultExtendedHandshakeClientVersion)
+ // fmt.Printf("Torrent version prefix: %q\n", version.DefaultBep20Prefix)
+ // return nil
+ //}()},
+ bargle.Subcommand{Name: "serve", Command: serve(), Desc: "creates and seeds a torrent from a filepath"},
)
+ main.Run()
}
"fmt"
"os"
- "github.com/anacrolix/args"
+ "github.com/anacrolix/bargle"
"github.com/anacrolix/torrent/metainfo"
"github.com/bradfitz/iter"
)
Files bool
}
-func metainfoCmd(ctx args.SubCmdCtx) (err error) {
+func metainfoCmd() (cmd bargle.Command) {
var metainfoPath string
var mi *metainfo.MetaInfo
- // TODO: Treat no subcommand as a failure.
- return ctx.NewParser().AddParams(
- args.Pos("torrent file", &metainfoPath, args.AfterParse(func() (err error) {
- mi, err = metainfo.LoadFromFile(metainfoPath)
- return
- })),
- args.Subcommand("magnet", func(ctx args.SubCmdCtx) (err error) {
- info, err := mi.UnmarshalInfo()
- if err != nil {
- return
- }
- fmt.Fprintf(os.Stdout, "%s\n", mi.Magnet(nil, &info).String())
- return nil
- }),
- args.Subcommand("pprint", func(ctx args.SubCmdCtx) (err error) {
- var flags pprintMetainfoFlags
- err = ctx.NewParser().AddParams(args.FromStruct(&flags)...).Parse()
- if err != nil {
- return
- }
- err = pprintMetainfo(mi, flags)
- if err != nil {
- return
- }
- if !flags.JustName {
- os.Stdout.WriteString("\n")
+ // TODO: Test if bargle treats no subcommand as a failure.
+ cmd.Positionals = append(cmd.Positionals,
+ &bargle.Positional[*string]{
+ Name: "torrent file",
+ Value: &metainfoPath,
+ AfterParseFunc: func(ctx bargle.Context) error {
+ ctx.AfterParse(func() (err error) {
+ mi, err = metainfo.LoadFromFile(metainfoPath)
+ return
+ })
+ return nil
+ },
+ },
+ bargle.Subcommand{Name: "magnet", Command: func() (cmd bargle.Command) {
+ cmd.DefaultAction = func() (err error) {
+ info, err := mi.UnmarshalInfo()
+ if err != nil {
+ return
+ }
+ fmt.Fprintf(os.Stdout, "%s\n", mi.Magnet(nil, &info).String())
+ return nil
}
return
- }),
- args.Subcommand("infohash", func(ctx args.SubCmdCtx) (err error) {
- fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), metainfoPath)
- return nil
- }),
- args.Subcommand("list-files", func(ctx args.SubCmdCtx) (err error) {
- info, err := mi.UnmarshalInfo()
- if err != nil {
- return fmt.Errorf("unmarshalling info from metainfo at %q: %v", metainfoPath, err)
- }
- for _, f := range info.UpvertedFiles() {
- fmt.Println(f.DisplayPath(&info))
- }
- return nil
- }),
- ).Parse()
+ }()},
+ //bargle.Subcommand{Name: "pprint", Command: func(ctx args.SubCmdCtx) (err error) {
+ // var flags pprintMetainfoFlags
+ // err = ctx.NewParser().AddParams(args.FromStruct(&flags)...).Parse()
+ // if err != nil {
+ // return
+ // }
+ // err = pprintMetainfo(mi, flags)
+ // if err != nil {
+ // return
+ // }
+ // if !flags.JustName {
+ // os.Stdout.WriteString("\n")
+ // }
+ // return
+ //}},
+ //bargle.Subcommand{Name: "infohash", Command: func(ctx args.SubCmdCtx) (err error) {
+ // fmt.Printf("%s: %s\n", mi.HashInfoBytes().HexString(), metainfoPath)
+ // return nil
+ //}},
+ //bargle.Subcommand{Name: "list-files", Command: func(ctx args.SubCmdCtx) (err error) {
+ // info, err := mi.UnmarshalInfo()
+ // if err != nil {
+ // return fmt.Errorf("unmarshalling info from metainfo at %q: %v", metainfoPath, err)
+ // }
+ // for _, f := range info.UpvertedFiles() {
+ // fmt.Println(f.DisplayPath(&info))
+ // }
+ // return nil
+ //}},
+ )
+ return
}
func pprintMetainfo(metainfo *metainfo.MetaInfo, flags pprintMetainfoFlags) error {
"net/http"
"path/filepath"
- "github.com/anacrolix/args"
+ "github.com/anacrolix/bargle"
"github.com/anacrolix/log"
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/storage"
)
-func serve(ctx args.SubCmdCtx) error {
- var filePath string
- ctx.Parse(args.Pos("filePath", &filePath))
- ctx.Defer(func() error {
+func serve() (cmd bargle.Command) {
+ filePath := &bargle.Positional[string]{}
+ cmd.Positionals = append(cmd.Positionals, filePath)
+ cmd.DefaultAction = func() error {
cfg := torrent.NewDefaultClientConfig()
cfg.Seed = true
cl, err := torrent.NewClient(cfg)
info := metainfo.Info{
PieceLength: pieceLength,
}
- err = info.BuildFromFilePath(filePath)
+ err = info.BuildFromFilePath(filePath.Value)
if err != nil {
- return fmt.Errorf("building info from path %q: %w", filePath, err)
+ return fmt.Errorf("building info from path %q: %w", filePath.Value, err)
}
for _, fi := range info.Files {
log.Printf("added %q", fi.Path)
to, _ := cl.AddTorrentOpt(torrent.AddTorrentOpts{
InfoHash: ih,
Storage: storage.NewFileOpts(storage.NewFileClientOpts{
- ClientBaseDir: filePath,
+ ClientBaseDir: filePath.Value,
FilePathMaker: func(opts storage.FilePathMakerOpts) string {
return filepath.Join(opts.File.Path...)
},
}
fmt.Printf("%v: %v\n", to, to.Metainfo().Magnet(&ih, &info))
select {}
- })
- return nil
+ }
+ return
}
require (
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
github.com/alexflint/go-scalar v1.1.0 // indirect
+ github.com/anacrolix/bargle v0.0.0-20220620083758-c3885e1796d1 // indirect
github.com/anacrolix/mmsg v1.0.0 // indirect
github.com/anacrolix/stm v0.4.0 // indirect
github.com/benbjohnson/immutable v0.3.0 // indirect
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/anacrolix/args v0.5.1-0.20220509024600-c3b77d0b61ac h1:XWoepbk3zgOQ8jMO3vpOnohd6MfENPbFZPivB2L7myc=
github.com/anacrolix/args v0.5.1-0.20220509024600-c3b77d0b61ac/go.mod h1:Fj/N2PehEwTBE5t/V/9xgTcxDkuYQ+5IBoFw/8gkldI=
+github.com/anacrolix/bargle v0.0.0-20220620083758-c3885e1796d1 h1:RijTNFCxug0EBODz/AmqJDA3Ow700v5jJZQL1j+RLvI=
+github.com/anacrolix/bargle v0.0.0-20220620083758-c3885e1796d1/go.mod h1:cC/kX8wL4i1n+63lOrXhPQQlsoxCo0EqV88fGExQwcY=
github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
github.com/anacrolix/dht/v2 v2.18.0 h1:btjVjzjKqO5nKGbJHJ2UmuwiRx+EgX3e+OCHC9+WRz8=