From aefce13f577f5cd8f9402c9a2f807af3a35905d2 Mon Sep 17 00:00:00 2001 From: David Allen Date: Wed, 24 Jul 2024 11:52:12 -0600 Subject: [PATCH] Refactored/reorganized utils --- internal/util/auth.go | 37 ++++++++++ internal/util/error.go | 25 +++++++ internal/util/net.go | 64 +++++++++++++++++ internal/util/path.go | 70 +++++++++++++++++++ internal/util/util.go | 151 ----------------------------------------- 5 files changed, 196 insertions(+), 151 deletions(-) create mode 100644 internal/util/auth.go create mode 100644 internal/util/error.go create mode 100644 internal/util/net.go create mode 100644 internal/util/path.go delete mode 100644 internal/util/util.go diff --git a/internal/util/auth.go b/internal/util/auth.go new file mode 100644 index 0000000..98ef88c --- /dev/null +++ b/internal/util/auth.go @@ -0,0 +1,37 @@ +package util + +import ( + "fmt" + "os" + + "github.com/spf13/viper" +) + +// LoadAccessToken() tries to load a JWT string from an environment +// variable, file, or config in that order. If loading the token +// fails with one options, it will fallback to the next option until +// all options are exhausted. +// +// Returns a token as a string with no error if successful. +// Alternatively, returns an empty string with an error if a token is +// not able to be loaded. +func LoadAccessToken(path string) (string, error) { + // try to load token from env var + testToken := os.Getenv("ACCESS_TOKEN") + if testToken != "" { + return testToken, nil + } + + // try reading access token from a file + b, err := os.ReadFile(path) + if err == nil { + return string(b), nil + } + + // TODO: try to load token from config + testToken = viper.GetString("access_token") + if testToken != "" { + return testToken, nil + } + return "", fmt.Errorf("failed toload token from environment variable, file, or config") +} diff --git a/internal/util/error.go b/internal/util/error.go new file mode 100644 index 0000000..addca80 --- /dev/null +++ b/internal/util/error.go @@ -0,0 +1,25 @@ +package util + +import "fmt" + +// FormatErrorList() is a wrapper function that unifies error list formatting +// and makes printing error lists consistent. +// +// NOTE: The error returned IS NOT an error in itself and may be a bit misleading. +// Instead, it is a single condensed error composed of all of the errors included +// in the errList argument. +func FormatErrorList(errList []error) error { + var err error + for i, e := range errList { + err = fmt.Errorf("\t[%d] %v\n", i, e) + i += 1 + } + return err +} + +// HasErrors() is a simple wrapper function to check if an error list contains +// errors. Having a function that clearly states its purpose helps to improve +// readibility although it may seem pointless. +func HasErrors(errList []error) bool { + return len(errList) > 0 +} diff --git a/internal/util/net.go b/internal/util/net.go new file mode 100644 index 0000000..cdc18db --- /dev/null +++ b/internal/util/net.go @@ -0,0 +1,64 @@ +package util + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "net" + "net/http" +) + +// GetNextIP() returns the next IP address, but does not account +// for net masks. +func GetNextIP(ip *net.IP, inc uint) *net.IP { + if ip == nil { + return &net.IP{} + } + i := ip.To4() + v := uint(i[0])<<24 + uint(i[1])<<16 + uint(i[2])<<8 + uint(i[3]) + v += inc + v3 := byte(v & 0xFF) + v2 := byte((v >> 8) & 0xFF) + v1 := byte((v >> 16) & 0xFF) + v0 := byte((v >> 24) & 0xFF) + // return &net.IP{[]byte{v0, v1, v2, v3}} + r := net.IPv4(v0, v1, v2, v3) + return &r +} + +// MakeRequest() is a wrapper function that condenses simple HTTP +// requests done to a single call. It expects an optional HTTP client, +// URL, HTTP method, request body, and request headers. This function +// is useful when making many requests where only these few arguments +// are changing. +// +// Returns a HTTP response object, response body as byte array, and any +// error that may have occurred with making the request. +func MakeRequest(client *http.Client, url string, httpMethod string, body []byte, headers map[string]string) (*http.Response, []byte, error) { + // use defaults if no client provided + if client == nil { + client = http.DefaultClient + client.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + } + req, err := http.NewRequest(httpMethod, url, bytes.NewBuffer(body)) + if err != nil { + return nil, nil, fmt.Errorf("failed to create new HTTP request: %v", err) + } + req.Header.Add("User-Agent", "magellan") + for k, v := range headers { + req.Header.Add(k, v) + } + res, err := client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("failed to make request: %v", err) + } + b, err := io.ReadAll(res.Body) + res.Body.Close() + if err != nil { + return nil, nil, fmt.Errorf("failed to read response body: %v", err) + } + return res, b, err +} diff --git a/internal/util/path.go b/internal/util/path.go new file mode 100644 index 0000000..06611b6 --- /dev/null +++ b/internal/util/path.go @@ -0,0 +1,70 @@ +package util + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "time" +) + +// PathExists() is a wrapper function that simplifies checking +// if a file or directory already exists at the provided path. +// +// Returns whether the path exists and no error if successful, +// otherwise, it returns false with an error. +func PathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +// SplitPathForViper() is an utility function to split a path into 3 parts: +// - directory +// - filename +// - extension +// The intent was to break a path into a format that's more easily consumable +// by spf13/viper's API. See the "LoadConfig()" function in internal/config.go +// for more details. +// +// TODO: Rename function to something more generalized. +func SplitPathForViper(path string) (string, string, string) { + filename := filepath.Base(path) + ext := filepath.Ext(filename) + return filepath.Dir(path), strings.TrimSuffix(filename, ext), strings.TrimPrefix(ext, ".") +} + +// MakeOutputDirectory() creates a new directory at the path argument if +// the path does not exist +// +// TODO: Refactor this function for hive partitioning or possibly move into +// the logging package. +// TODO: Add an option to force overwriting the path. +func MakeOutputDirectory(path string) (string, error) { + // get the current data + time using Go's stupid formatting + t := time.Now() + dirname := t.Format("2006-01-01 15:04:05") + final := path + "/" + dirname + + // check if path is valid and directory + pathExists, err := PathExists(final) + if err != nil { + return final, fmt.Errorf("failed to check for existing path: %v", err) + } + if pathExists { + // make sure it is directory with 0o644 permissions + return final, fmt.Errorf("found existing path: %v", final) + } + + // create directory with data + time + err = os.MkdirAll(final, 0766) + if err != nil { + return final, fmt.Errorf("failed to make directory: %v", err) + } + return final, nil +} diff --git a/internal/util/util.go b/internal/util/util.go deleted file mode 100644 index 6817f4a..0000000 --- a/internal/util/util.go +++ /dev/null @@ -1,151 +0,0 @@ -package util - -import ( - "bytes" - "crypto/tls" - "fmt" - "io" - "net" - "net/http" - "os" - "path/filepath" - "strings" - "time" -) - -// PathExists() is a wrapper function that simplifies checking -// if a file or directory already exists at the provided path. -// -// Returns whether the path exists and no error if successful, -// otherwise, it returns false with an error. -func PathExists(path string) (bool, error) { - _, err := os.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return false, err -} - -// GetNextIP() returns the next IP address, but does not account -// for net masks. -func GetNextIP(ip *net.IP, inc uint) *net.IP { - if ip == nil { - return &net.IP{} - } - i := ip.To4() - v := uint(i[0])<<24 + uint(i[1])<<16 + uint(i[2])<<8 + uint(i[3]) - v += inc - v3 := byte(v & 0xFF) - v2 := byte((v >> 8) & 0xFF) - v1 := byte((v >> 16) & 0xFF) - v0 := byte((v >> 24) & 0xFF) - // return &net.IP{[]byte{v0, v1, v2, v3}} - r := net.IPv4(v0, v1, v2, v3) - return &r -} - -// MakeRequest() is a wrapper function that condenses simple HTTP -// requests done to a single call. It expects an optional HTTP client, -// URL, HTTP method, request body, and request headers. This function -// is useful when making many requests where only these few arguments -// are changing. -// -// Returns a HTTP response object, response body as byte array, and any -// error that may have occurred with making the request. -func MakeRequest(client *http.Client, url string, httpMethod string, body []byte, headers map[string]string) (*http.Response, []byte, error) { - // use defaults if no client provided - if client == nil { - client = http.DefaultClient - client.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - } - req, err := http.NewRequest(httpMethod, url, bytes.NewBuffer(body)) - if err != nil { - return nil, nil, fmt.Errorf("failed to create new HTTP request: %v", err) - } - req.Header.Add("User-Agent", "magellan") - for k, v := range headers { - req.Header.Add(k, v) - } - res, err := client.Do(req) - if err != nil { - return nil, nil, fmt.Errorf("failed to make request: %v", err) - } - b, err := io.ReadAll(res.Body) - res.Body.Close() - if err != nil { - return nil, nil, fmt.Errorf("failed to read response body: %v", err) - } - return res, b, err -} - -// MakeOutputDirectory() creates a new directory at the path argument if -// the path does not exist -// -// TODO: Refactor this function for hive partitioning or possibly move into -// the logging package. -// TODO: Add an option to force overwriting the path. -func MakeOutputDirectory(path string) (string, error) { - // get the current data + time using Go's stupid formatting - t := time.Now() - dirname := t.Format("2006-01-01 15:04:05") - final := path + "/" + dirname - - // check if path is valid and directory - pathExists, err := PathExists(final) - if err != nil { - return final, fmt.Errorf("failed to check for existing path: %v", err) - } - if pathExists { - // make sure it is directory with 0o644 permissions - return final, fmt.Errorf("found existing path: %v", final) - } - - // create directory with data + time - err = os.MkdirAll(final, 0766) - if err != nil { - return final, fmt.Errorf("failed to make directory: %v", err) - } - return final, nil -} - -// SplitPathForViper() is an utility function to split a path into 3 parts: -// - directory -// - filename -// - extension -// The intent was to break a path into a format that's more easily consumable -// by spf13/viper's API. See the "LoadConfig()" function in internal/config.go -// for more details. -// -// TODO: Rename function to something more generalized. -func SplitPathForViper(path string) (string, string, string) { - filename := filepath.Base(path) - ext := filepath.Ext(filename) - return filepath.Dir(path), strings.TrimSuffix(filename, ext), strings.TrimPrefix(ext, ".") -} - -// FormatErrorList() is a wrapper function that unifies error list formatting -// and makes printing error lists consistent. -// -// NOTE: The error returned IS NOT an error in itself and may be a bit misleading. -// Instead, it is a single condensed error composed of all of the errors included -// in the errList argument. -func FormatErrorList(errList []error) error { - var err error - for i, e := range errList { - err = fmt.Errorf("\t[%d] %v\n", i, e) - i += 1 - } - return err -} - -// HasErrors() is a simple wrapper function to check if an error list contains -// errors. Having a function that clearly states its purpose helps to improve -// readibility although it may seem pointless. -func HasErrors(errList []error) bool { - return len(errList) > 0 -}