From 6b28488fbdfe8f3dc359b35a35751f285a7582e2 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Thu, 11 Mar 2021 05:50:04 +0300 Subject: [PATCH] Move cli to separate package --- cli.go | 36 --------- cli_access.go => cli/access.go | 29 ++++--- cli/base.go | 77 +++++++++++++++++++ cli/cli.go | 11 +++ .../generate_secret.go | 8 +- main.go | 9 +-- mtglib/network/init.go | 2 +- 7 files changed, 114 insertions(+), 58 deletions(-) delete mode 100644 cli.go rename cli_access.go => cli/access.go (84%) create mode 100644 cli/base.go create mode 100644 cli/cli.go rename cli_generate_secret.go => cli/generate_secret.go (79%) diff --git a/cli.go b/cli.go deleted file mode 100644 index 78373d3..0000000 --- a/cli.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - - "github.com/9seconds/mtg/v2/config" - "github.com/9seconds/mtg/v2/mtglib/network" -) - -type cli struct { - network network.Network - conf *config.Config -} - -func (c *cli) ReadConfig(path string) error { - content, err := ioutil.ReadFile(path) - if err != nil { - return fmt.Errorf("cannot read config file: %w", err) - } - - conf, err := config.Parse(content) - if err != nil { - return fmt.Errorf("cannot parse config: %w", err) - } - - ntw, err := makeNetwork(conf) - if err != nil { - return fmt.Errorf("cannot build a network: %w", err) - } - - c.conf = conf - c.network = ntw - - return nil -} diff --git a/cli_access.go b/cli/access.go similarity index 84% rename from cli_access.go rename to cli/access.go index 7036231..b8fdc97 100644 --- a/cli_access.go +++ b/cli/access.go @@ -1,9 +1,10 @@ -package main +package cli import ( "context" "encoding/json" "fmt" + "io" "io/ioutil" "net" "net/http" @@ -30,14 +31,14 @@ type accessResponseURLs struct { TmeQrCode string `json:"tme_qrcode"` } -type cliCommandAccess struct { - cli +type Access struct { + base ConfigPath string `arg required type:"existingfile" help:"Path to the configuration file." name:"config-path"` // nolint: lll, govet Hex bool `help:"Print secret in hex encoding."` } -func (c *cliCommandAccess) Run(cli *CLI) error { +func (c *Access) Run(cli *CLI) error { if err := c.ReadConfig(cli.Access.ConfigPath); err != nil { return fmt.Errorf("cannot init config: %w", err) } @@ -72,7 +73,7 @@ func (c *cliCommandAccess) Run(cli *CLI) error { return nil } -func (c *cliCommandAccess) getIP(protocol string) net.IP { +func (c *Access) getIP(protocol string) net.IP { client := c.network.MakeHTTPClient(0) client.Transport = &http.Transport{ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { @@ -80,9 +81,14 @@ func (c *cliCommandAccess) getIP(protocol string) net.IP { }, } - c.network.PatchHTTPClient(client) + c.network.PrepareHTTPClient(client) - resp, err := client.Get("https://ifconfig.co") // nolint: bodyclose, noctx + req, err := http.NewRequest(http.MethodGet, "https://ifconfig.co", nil) + if err != nil { + panic(err) + } + + resp, err := client.Do(req) if err != nil { return nil } @@ -91,7 +97,10 @@ func (c *cliCommandAccess) getIP(protocol string) net.IP { return nil } - defer exhaustResponse(resp) + defer func() { + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() + }() data, err := ioutil.ReadAll(resp.Body) if err != nil { @@ -101,7 +110,7 @@ func (c *cliCommandAccess) getIP(protocol string) net.IP { return net.ParseIP(strings.TrimSpace(string(data))) } -func (c *cliCommandAccess) makeURLs(ip net.IP, cli *CLI) *accessResponseURLs { +func (c *Access) makeURLs(ip net.IP, cli *CLI) *accessResponseURLs { if ip == nil { return nil } @@ -140,7 +149,7 @@ func (c *cliCommandAccess) makeURLs(ip net.IP, cli *CLI) *accessResponseURLs { return rv } -func (c *cliCommandAccess) makeQRCode(data string) string { +func (c *Access) makeQRCode(data string) string { values := url.Values{} values.Set("qzone", "4") diff --git a/cli/base.go b/cli/base.go new file mode 100644 index 0000000..7736592 --- /dev/null +++ b/cli/base.go @@ -0,0 +1,77 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "net" + "net/url" + + "github.com/9seconds/mtg/v2/config" + "github.com/9seconds/mtg/v2/mtglib/network" +) + +type base struct { + network network.Network + conf *config.Config +} + +func (b *base) ReadConfig(path string) error { + content, err := ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("cannot read config file: %w", err) + } + + conf, err := config.Parse(content) + if err != nil { + return fmt.Errorf("cannot parse config: %w", err) + } + + ntw, err := b.makeNetwork(conf) + if err != nil { + return fmt.Errorf("cannot build a network: %w", err) + } + + b.conf = conf + b.network = ntw + + return nil +} + +func (b *base) makeNetwork(conf *config.Config) (network.Network, error) { + tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout) + idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout) + dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String() + bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize) + + baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize)) + if err != nil { + return nil, fmt.Errorf("cannot build a default dialer: %w", err) + } + + proxyURLs := make([]*url.URL, 0, len(conf.Network.Proxies)) + + for _, v := range conf.Network.Proxies { + if value := v.Value(nil); value != nil { + proxyURLs = append(proxyURLs, v.Value(nil)) + } + } + + switch len(proxyURLs) { + case 0: + return network.NewNetwork(baseDialer, dohIP, idleTimeout) + case 1: + socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0]) + if err != nil { + return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) + } + + return network.NewNetwork(socksDialer, dohIP, idleTimeout) + } + + socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs) + if err != nil { + return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) + } + + return network.NewNetwork(socksDialer, dohIP, idleTimeout) +} diff --git a/cli/cli.go b/cli/cli.go new file mode 100644 index 0000000..9f27d72 --- /dev/null +++ b/cli/cli.go @@ -0,0 +1,11 @@ +package cli + +import ( + "github.com/alecthomas/kong" +) + +type CLI struct { + GenerateSecret GenerateSecret `cmd help:"Generate new proxy secret"` // nolint: govet + Access Access `cmd help:"Print access information."` // nolint: govet + Version kong.VersionFlag `help:"Print version."` +} diff --git a/cli_generate_secret.go b/cli/generate_secret.go similarity index 79% rename from cli_generate_secret.go rename to cli/generate_secret.go index 41f8b04..a92e9cc 100644 --- a/cli_generate_secret.go +++ b/cli/generate_secret.go @@ -1,4 +1,4 @@ -package main +package cli import ( "fmt" @@ -6,14 +6,14 @@ import ( "github.com/9seconds/mtg/v2/mtglib" ) -type cliCommandGenerateSecret struct { - cli +type GenerateSecret struct { + base HostName string `arg optional help:"Hostname to use for domain fronting. Default is '${domain_front}'." name:"hostname" default:"${domain_front}"` // nolint: lll, govet Hex bool `help:"Print secret in hex encoding."` } -func (c *cliCommandGenerateSecret) Run(cli *CLI) error { // nolint: unparam +func (c *GenerateSecret) Run(cli *CLI) error { // nolint: unparam secret := mtglib.GenerateSecret(cli.GenerateSecret.HostName) if cli.GenerateSecret.Hex { diff --git a/main.go b/main.go index b4cf3f6..622ed5c 100644 --- a/main.go +++ b/main.go @@ -4,21 +4,16 @@ import ( "math/rand" "time" + "github.com/9seconds/mtg/v2/cli" "github.com/alecthomas/kong" ) var version = "dev" // has to be set by ldflags -type CLI struct { - GenerateSecret cliCommandGenerateSecret `cmd help:"Generate new proxy secret"` // nolint: govet - Access cliCommandAccess `cmd help:"Print access information."` // nolint: govet - Version kong.VersionFlag `help:"Print version."` -} - func main() { rand.Seed(time.Now().UTC().UnixNano()) - cli := &CLI{} + cli := &cli.CLI{} ctx := kong.Parse(cli, kong.Vars{ "domain_front": "amazonaws.com", "version": version, diff --git a/mtglib/network/init.go b/mtglib/network/init.go index d922ce1..9be2dcc 100644 --- a/mtglib/network/init.go +++ b/mtglib/network/init.go @@ -39,5 +39,5 @@ type Network interface { DNSResolve(network, hostname string) (ips []string, err error) MakeHTTPClient(timeout time.Duration) *http.Client IdleTimeout() time.Duration - PatchHTTPClient(*http.Client) + PrepareHTTPClient(*http.Client) }