diff --git a/cmd/main.go b/cmd/main.go index 6f65f09..d0ac2e2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,110 +1,94 @@ package main import ( - "flag" "fmt" - nested "github.com/antonfisher/nested-logrus-formatter" - "github.com/sirupsen/logrus" - "github.com/yosuke-furukawa/json5/encoding/json5" "io/ioutil" "os" "strings" + "time" + + nested "github.com/antonfisher/nested-logrus-formatter" + "github.com/sirupsen/logrus" + "github.com/yosuke-furukawa/json5/encoding/json5" + + "github.com/urfave/cli/v2" ) -// Injected when compiling var ( appVersion = "Unknown" appCommit = "Unknown" appDate = "Unknown" ) -var ( - configPath = flag.String("config", "config.json", "Config file") - showVersion = flag.Bool("version", false, "Show version") - disableUpdateCheck = flag.Bool("no-check", false, "Disable update check") -) - -func init() { - logrus.SetOutput(os.Stdout) - - lvl, err := logrus.ParseLevel(os.Getenv("LOGGING_LEVEL")) - if err == nil { - logrus.SetLevel(lvl) - } else { - logrus.SetLevel(logrus.DebugLevel) - } - - // tsFormat is used to format the log timestamp, by default(empty) - // the RFC3339("2006-01-02T15:04:05Z07:00") format is used. - // The user can use environment variable to override the default - // timestamp format(e.g. "2006-01-02 15:04:05"). - tsFormat := os.Getenv("LOGGING_TIMESTAMP_FORMAT") - - fmtter := os.Getenv("LOGGING_FORMATTER") - if strings.ToLower(fmtter) == "json" { - logrus.SetFormatter(&logrus.JSONFormatter{ - TimestampFormat: tsFormat, - }) - } else { - logrus.SetFormatter(&nested.Formatter{ - FieldsOrder: []string{ - "version", "url", - "config", "file", "mode", - "addr", "src", "dst", "session", "action", - "error", +func main() { + app := &cli.App{ + Name: "Hysteria", + Usage: "a TCP/UDP relay & SOCKS5/HTTP proxy tool optimized for poor network environments", + Version: fmt.Sprintf("%s %s %s", appVersion, appDate, appCommit), + Authors: []*cli.Author{{Name: "HyNetwork "}}, + EnableBashCompletion: true, + Action: clientAction, + Flags: commonFlags(), + Before: initApp, + Commands: []*cli.Command{ + { + Name: "server", + Usage: "Run as server mode", + Action: serverAction, }, - TimestampFormat: tsFormat, - }) + { + Name: "client", + Usage: "Run as client mode", + Action: clientAction, + }, + }, + } + + err := app.Run(os.Args) + if err != nil { + logrus.Fatal(err) } - flag.Parse() } -func main() { - if *showVersion { - // Print version and quit - fmt.Printf("%-10s%s\n", "Version:", appVersion) - fmt.Printf("%-10s%s\n", "Commit:", appCommit) - fmt.Printf("%-10s%s\n", "Date:", appDate) - return - } - if !*disableUpdateCheck { - go checkUpdate() - } - cb, err := ioutil.ReadFile(*configPath) +func clientAction(c *cli.Context) error { + cbs, err := ioutil.ReadFile(c.String("config")) if err != nil { logrus.WithFields(logrus.Fields{ - "file": *configPath, + "file": c.String("config"), "error": err, }).Fatal("Failed to read configuration") } - mode := flag.Arg(0) - if strings.EqualFold(mode, "server") { - // server mode - c, err := parseServerConfig(cb) - if err != nil { - logrus.WithFields(logrus.Fields{ - "file": *configPath, - "error": err, - }).Fatal("Failed to parse server configuration") - } - server(c) - } else if len(mode) == 0 || strings.EqualFold(mode, "client") { - // client mode - c, err := parseClientConfig(cb) - if err != nil { - logrus.WithFields(logrus.Fields{ - "file": *configPath, - "error": err, - }).Fatal("Failed to parse client configuration") - } - client(c) - } else { - // invalid - fmt.Println() - fmt.Printf("Usage: %s MODE [OPTIONS]\n\n"+ - "Available modes: server, client\n\n", os.Args[0]) + // client mode + cc, err := parseClientConfig(cbs) + if err != nil { + logrus.WithFields(logrus.Fields{ + "file": c.String("config"), + "error": err, + }).Fatal("Failed to parse client configuration") } + client(cc) + return nil +} + +func serverAction(c *cli.Context) error { + cbs, err := ioutil.ReadFile(c.String("config")) + if err != nil { + logrus.WithFields(logrus.Fields{ + "file": c.String("config"), + "error": err, + }).Fatal("Failed to read configuration") + } + // server mode + sc, err := parseServerConfig(cbs) + if err != nil { + logrus.WithFields(logrus.Fields{ + "file": c.String("config"), + "error": err, + }).Fatal("Failed to parse server configuration") + } + server(sc) + return nil } func parseServerConfig(cb []byte) (*serverConfig, error) { @@ -124,3 +108,71 @@ func parseClientConfig(cb []byte) (*clientConfig, error) { } return &c, c.Check() } + +func initApp(c *cli.Context) error { + logrus.SetOutput(os.Stdout) + + lvl, err := logrus.ParseLevel(c.String("log-level")) + if err == nil { + logrus.SetLevel(lvl) + } else { + logrus.SetLevel(logrus.InfoLevel) + } + + if strings.ToLower(c.String("log-format")) == "json" { + logrus.SetFormatter(&logrus.JSONFormatter{ + TimestampFormat: c.String("log-timestamp"), + }) + } else { + logrus.SetFormatter(&nested.Formatter{ + FieldsOrder: []string{ + "version", "url", + "config", "file", "mode", + "addr", "src", "dst", "session", "action", + "error", + }, + TimestampFormat: c.String("log-timestamp"), + }) + } + + if !c.Bool("no-check") { + go checkUpdate() + } + + return nil +} + +func commonFlags() []cli.Flag { + return []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "config file", + EnvVars: []string{"HYSTERIA_CONFIG"}, + Value: "./config.json", + }, + &cli.StringFlag{ + Name: "log-level", + Usage: "log level", + EnvVars: []string{"HYSTERIA_LOG_LEVEL", "LOGGING_LEVEL"}, + Value: "info", + }, + &cli.StringFlag{ + Name: "log-timestamp", + Usage: "log timestamp format", + EnvVars: []string{"HYSTERIA_LOG_TIMESTAMP", "LOGGING_TIMESTAMP_FORMAT"}, + Value: time.RFC3339, + }, + &cli.StringFlag{ + Name: "log-format", + Usage: "log output format", + EnvVars: []string{"HYSTERIA_LOG_FORMAT", "LOGGING_FORMATTER"}, + Value: "txt", + }, + &cli.BoolFlag{ + Name: "no-check", + Usage: "disable update check", + EnvVars: []string{"HYSTERIA_CHECK_UPDATE"}, + }, + } +} diff --git a/cmd/update.go b/cmd/update.go index ba3b7bb..9c03ee6 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -2,10 +2,11 @@ package main import ( "encoding/json" - "github.com/sirupsen/logrus" "io/ioutil" "net/http" "time" + + "github.com/sirupsen/logrus" ) const githubAPIURL = "https://api.github.com/repos/HyNetwork/hysteria/releases/latest" diff --git a/go.mod b/go.mod index 9bb464f..c5c9985 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed github.com/antonfisher/nested-logrus-formatter v1.3.1 github.com/caddyserver/certmagic v0.13.1 + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e github.com/hashicorp/golang-lru v0.5.4 @@ -13,10 +14,12 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/prometheus/client_golang v1.10.0 + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.8.1 github.com/txthinking/runnergroup v0.0.0-20210326110939-37fc67d0da7c // indirect github.com/txthinking/socks5 v0.0.0-20210326104807-61b5745ff346 github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe // indirect + github.com/urfave/cli/v2 v2.3.0 github.com/yosuke-furukawa/json5 v0.1.1 golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect ) diff --git a/go.sum b/go.sum index f9bbda3..22f2641 100644 --- a/go.sum +++ b/go.sum @@ -58,6 +58,8 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -321,8 +323,11 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -383,7 +388,10 @@ github.com/txthinking/socks5 v0.0.0-20210326104807-61b5745ff346/go.mod h1:d3n8NJ github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe h1:gMWxZxBFRAXqoGkwkYlPX2zvyyKNWJpxOxCrjqJkm5A= github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe/go.mod h1:WgqbSEmUYSjEV3B1qmee/PpP2NYEz4bL9/+mF1ma+s4= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -585,6 +593,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=