From a921f9848c8f5bce7ab63e5aced6770ce23b0f57 Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Tue, 29 Dec 2020 18:24:03 +0000 Subject: [PATCH] Code maintenance: CLI interface abstraction --- cmd/gluetun/main.go | 6 +- internal/cli/cli.go | 138 ++-------------------------------- internal/cli/clientkey.go | 41 ++++++++++ internal/cli/healthcheck.go | 20 +++++ internal/cli/openvpnconfig.go | 48 ++++++++++++ internal/cli/update.go | 64 ++++++++++++++++ 6 files changed, 185 insertions(+), 132 deletions(-) create mode 100644 internal/cli/clientkey.go create mode 100644 internal/cli/healthcheck.go create mode 100644 internal/cli/openvpnconfig.go create mode 100644 internal/cli/update.go diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index 8f43a154..66c10b34 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -56,12 +56,14 @@ func main() { os := os.New() osUser := user.New() unix := unix.New() - nativeos.Exit(_main(ctx, buildInfo, args, os, osUser, unix)) + cli := cli.New() + nativeos.Exit(_main(ctx, buildInfo, args, os, osUser, unix, cli)) } //nolint:gocognit,gocyclo func _main(background context.Context, buildInfo models.BuildInformation, - args []string, os os.OS, osUser user.OSUser, unix unix.Unix) int { + args []string, os os.OS, osUser user.OSUser, unix unix.Unix, + cli cli.CLI) int { if len(args) > 1 { // cli operation var err error switch args[1] { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 6fb90b3a..7e4a2a4d 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -2,141 +2,19 @@ package cli import ( "context" - "flag" - "fmt" - "io/ioutil" - "net/http" - "strings" - "time" - "github.com/qdm12/gluetun/internal/constants" - "github.com/qdm12/gluetun/internal/healthcheck" "github.com/qdm12/gluetun/internal/os" - "github.com/qdm12/gluetun/internal/params" - "github.com/qdm12/gluetun/internal/provider" - "github.com/qdm12/gluetun/internal/settings" - "github.com/qdm12/gluetun/internal/storage" - "github.com/qdm12/gluetun/internal/updater" - "github.com/qdm12/golibs/logging" ) -func ClientKey(args []string, openFile os.OpenFileFunc) error { - flagSet := flag.NewFlagSet("clientkey", flag.ExitOnError) - filepath := flagSet.String("path", string(constants.ClientKey), "file path to the client.key file") - if err := flagSet.Parse(args); err != nil { - return err - } - file, err := openFile(*filepath, os.O_RDONLY, 0) - if err != nil { - return err - } - data, err := ioutil.ReadAll(file) - if err != nil { - _ = file.Close() - return err - } - if err := file.Close(); err != nil { - return err - } - if err != nil { - return err - } - s := string(data) - s = strings.ReplaceAll(s, "\n", "") - s = strings.ReplaceAll(s, "\r", "") - s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----") - s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----") - fmt.Println(s) - return nil +type CLI interface { + ClientKey(args []string, openFile os.OpenFileFunc) error + HealthCheck(ctx context.Context) error + OpenvpnConfig(os os.OS) error + Update(args []string, os os.OS) error } -func HealthCheck(ctx context.Context) error { - const timeout = 3 * time.Second - httpClient := &http.Client{Timeout: timeout} - healthchecker := healthcheck.NewChecker(httpClient) - ctx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - const url = "http://" + constants.HealthcheckAddress - return healthchecker.Check(ctx, url) -} +type cli struct{} -func OpenvpnConfig(os os.OS) error { - logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel) - if err != nil { - return err - } - paramsReader := params.NewReader(logger, os) - allSettings, err := settings.GetAllSettings(paramsReader) - if err != nil { - return err - } - allServers, err := storage.New(logger, os, constants.ServersData). - SyncServers(constants.GetAllServers()) - if err != nil { - return err - } - providerConf := provider.New(allSettings.OpenVPN.Provider.Name, allServers, time.Now) - connection, err := providerConf.GetOpenVPNConnection(allSettings.OpenVPN.Provider.ServerSelection) - if err != nil { - return err - } - lines := providerConf.BuildConf( - connection, - allSettings.OpenVPN.Verbosity, - "nonroortuser", - allSettings.OpenVPN.Root, - allSettings.OpenVPN.Cipher, - allSettings.OpenVPN.Auth, - allSettings.OpenVPN.Provider.ExtraConfigOptions, - ) - fmt.Println(strings.Join(lines, "\n")) - return nil -} - -func Update(args []string, os os.OS) error { - options := settings.Updater{CLI: true} - var flushToFile bool - flagSet := flag.NewFlagSet("update", flag.ExitOnError) - flagSet.BoolVar(&flushToFile, "file", false, "Write results to /gluetun/servers.json (for end users)") - flagSet.BoolVar(&options.Stdout, "stdout", false, "Write results to console to modify the program (for maintainers)") - flagSet.StringVar(&options.DNSAddress, "dns", "1.1.1.1", "DNS resolver address to use") - flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers") - flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers") - flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers") - flagSet.BoolVar(&options.PIA, "pia", false, "Update Private Internet Access post-summer 2020 servers") - flagSet.BoolVar(&options.Privado, "privado", false, "Update Privado servers") - flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers") - flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers") - flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers") - flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers") - if err := flagSet.Parse(args); err != nil { - return err - } - logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel) - if err != nil { - return err - } - if !flushToFile && !options.Stdout { - return fmt.Errorf("at least one of -file or -stdout must be specified") - } - ctx := context.Background() - const clientTimeout = 10 * time.Second - httpClient := &http.Client{Timeout: clientTimeout} - storage := storage.New(logger, os, constants.ServersData) - currentServers, err := storage.SyncServers(constants.GetAllServers()) - if err != nil { - return fmt.Errorf("cannot update servers: %w", err) - } - updater := updater.New(options, httpClient, currentServers, logger) - allServers, err := updater.UpdateServers(ctx) - if err != nil { - return err - } - if flushToFile { - if err := storage.FlushToFile(allServers); err != nil { - return fmt.Errorf("cannot update servers: %w", err) - } - } - - return nil +func New() CLI { + return &cli{} } diff --git a/internal/cli/clientkey.go b/internal/cli/clientkey.go new file mode 100644 index 00000000..b7708a69 --- /dev/null +++ b/internal/cli/clientkey.go @@ -0,0 +1,41 @@ +package cli + +import ( + "flag" + "fmt" + "io/ioutil" + "strings" + + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/os" +) + +func (c *cli) ClientKey(args []string, openFile os.OpenFileFunc) error { + flagSet := flag.NewFlagSet("clientkey", flag.ExitOnError) + filepath := flagSet.String("path", string(constants.ClientKey), "file path to the client.key file") + if err := flagSet.Parse(args); err != nil { + return err + } + file, err := openFile(*filepath, os.O_RDONLY, 0) + if err != nil { + return err + } + data, err := ioutil.ReadAll(file) + if err != nil { + _ = file.Close() + return err + } + if err := file.Close(); err != nil { + return err + } + if err != nil { + return err + } + s := string(data) + s = strings.ReplaceAll(s, "\n", "") + s = strings.ReplaceAll(s, "\r", "") + s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----") + s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----") + fmt.Println(s) + return nil +} diff --git a/internal/cli/healthcheck.go b/internal/cli/healthcheck.go new file mode 100644 index 00000000..2e3479ac --- /dev/null +++ b/internal/cli/healthcheck.go @@ -0,0 +1,20 @@ +package cli + +import ( + "context" + "net/http" + "time" + + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/healthcheck" +) + +func (c *cli) HealthCheck(ctx context.Context) error { + const timeout = 3 * time.Second + httpClient := &http.Client{Timeout: timeout} + healthchecker := healthcheck.NewChecker(httpClient) + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + const url = "http://" + constants.HealthcheckAddress + return healthchecker.Check(ctx, url) +} diff --git a/internal/cli/openvpnconfig.go b/internal/cli/openvpnconfig.go new file mode 100644 index 00000000..56dcad68 --- /dev/null +++ b/internal/cli/openvpnconfig.go @@ -0,0 +1,48 @@ +package cli + +import ( + "fmt" + "strings" + "time" + + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/os" + "github.com/qdm12/gluetun/internal/params" + "github.com/qdm12/gluetun/internal/provider" + "github.com/qdm12/gluetun/internal/settings" + "github.com/qdm12/gluetun/internal/storage" + "github.com/qdm12/golibs/logging" +) + +func (c *cli) OpenvpnConfig(os os.OS) error { + logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel) + if err != nil { + return err + } + paramsReader := params.NewReader(logger, os) + allSettings, err := settings.GetAllSettings(paramsReader) + if err != nil { + return err + } + allServers, err := storage.New(logger, os, constants.ServersData). + SyncServers(constants.GetAllServers()) + if err != nil { + return err + } + providerConf := provider.New(allSettings.OpenVPN.Provider.Name, allServers, time.Now) + connection, err := providerConf.GetOpenVPNConnection(allSettings.OpenVPN.Provider.ServerSelection) + if err != nil { + return err + } + lines := providerConf.BuildConf( + connection, + allSettings.OpenVPN.Verbosity, + "nonroortuser", + allSettings.OpenVPN.Root, + allSettings.OpenVPN.Cipher, + allSettings.OpenVPN.Auth, + allSettings.OpenVPN.Provider.ExtraConfigOptions, + ) + fmt.Println(strings.Join(lines, "\n")) + return nil +} diff --git a/internal/cli/update.go b/internal/cli/update.go new file mode 100644 index 00000000..ed8f1c23 --- /dev/null +++ b/internal/cli/update.go @@ -0,0 +1,64 @@ +package cli + +import ( + "context" + "flag" + "fmt" + "net/http" + "time" + + "github.com/qdm12/gluetun/internal/constants" + "github.com/qdm12/gluetun/internal/os" + "github.com/qdm12/gluetun/internal/settings" + "github.com/qdm12/gluetun/internal/storage" + "github.com/qdm12/gluetun/internal/updater" + "github.com/qdm12/golibs/logging" +) + +func (c *cli) Update(args []string, os os.OS) error { + options := settings.Updater{CLI: true} + var flushToFile bool + flagSet := flag.NewFlagSet("update", flag.ExitOnError) + flagSet.BoolVar(&flushToFile, "file", false, "Write results to /gluetun/servers.json (for end users)") + flagSet.BoolVar(&options.Stdout, "stdout", false, "Write results to console to modify the program (for maintainers)") + flagSet.StringVar(&options.DNSAddress, "dns", "1.1.1.1", "DNS resolver address to use") + flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers") + flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers") + flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers") + flagSet.BoolVar(&options.PIA, "pia", false, "Update Private Internet Access post-summer 2020 servers") + flagSet.BoolVar(&options.Privado, "privado", false, "Update Privado servers") + flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers") + flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers") + flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers") + flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers") + if err := flagSet.Parse(args); err != nil { + return err + } + logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel) + if err != nil { + return err + } + if !flushToFile && !options.Stdout { + return fmt.Errorf("at least one of -file or -stdout must be specified") + } + ctx := context.Background() + const clientTimeout = 10 * time.Second + httpClient := &http.Client{Timeout: clientTimeout} + storage := storage.New(logger, os, constants.ServersData) + currentServers, err := storage.SyncServers(constants.GetAllServers()) + if err != nil { + return fmt.Errorf("cannot update servers: %w", err) + } + updater := updater.New(options, httpClient, currentServers, logger) + allServers, err := updater.UpdateServers(ctx) + if err != nil { + return err + } + if flushToFile { + if err := storage.FlushToFile(allServers); err != nil { + return fmt.Errorf("cannot update servers: %w", err) + } + } + + return nil +}