package utils
import (
"errors"
"fmt"
"net/url"
"reflect"
"strings"
)
// IsInterfaceNil checks if an interface is nil
// This function required since interface in Go is considered nil
// only if both its type and value are nil. So, it's quite possible that
// an interface is not nil but the value it holds is nil.
func IsInterfaceNil(i interface{}) bool {
if i == nil {
return true
}
val := reflect.ValueOf(i)
switch val.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return val.IsNil()
case reflect.Invalid:
return true
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Array,
reflect.String, reflect.Struct, reflect.UnsafePointer:
return val.IsZero()
default:
return false
}
}
// UnwrapError unwraps the error to the original error
func UnwrapError(err error) error {
for {
// Unwrap returns the next error in the chain or nil
unwrapped := errors.Unwrap(err)
if unwrapped == nil {
return err // original error if nothing to unwrap
}
err = unwrapped
}
}
// LastErrorWithUnwrappedDepth returns the last error with the specified depth
func LastErrorWithUnwrappedDepth(err error, depth int) error {
var messages []string
current := err
for i := 0; i < depth && current != nil; i++ {
messages = append(messages, current.Error())
current = errors.Unwrap(current)
}
if len(messages) == 0 {
return err
}
// Join the collected error messages into a single error message.
formatted := messages[0]
for _, msg := range messages[1:] {
formatted = fmt.Sprintf("%s: %s", msg, formatted)
}
return errors.New(formatted)
}
func SliceToMap(slice []string) map[string]string {
mapVal := make(map[string]string)
for _, val := range slice {
mapVal[val] = val
}
return mapVal
}
func ExtractHost(rawURL string) string {
if rawURL == "*" {
return rawURL
}
if !strings.Contains(rawURL, "://") {
rawURL = "http://" + rawURL
}
parsedURL, err := url.Parse(rawURL)
if err == nil {
return parsedURL.Host
}
// As a fallback, split rawURL manually
parts := strings.SplitN(rawURL, "/", 2)
host := parts[0]
host = strings.TrimPrefix(host, "www.")
return host
}
func ExtractPath(rawURL string) string {
if rawURL == "" {
return ""
}
if !strings.Contains(rawURL, "://") {
rawURL = "http://" + rawURL
}
parsedURL, err := url.Parse(rawURL)
if err == nil {
return parsedURL.Path
}
// As a fallback, split rawURL manually
parts := strings.SplitN(rawURL, "/", 2)
path := ""
if len(parts) > 1 {
path = "/" + parts[1]
}
return path
}