516 lines
12 KiB
Go
516 lines
12 KiB
Go
package helper
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"reflect"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
"unicode"
|
|
|
|
"github.com/gookit/goutil/dump"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
// const (
|
|
// COLOR_Reset = "\033[0m"
|
|
// COLOR_Red = "\033[31m"
|
|
// COLOR_Green = "\033[32m"
|
|
// COLOR_Yellow = "\033[33m"
|
|
// COLOR_Blue = "\033[34m"
|
|
// COLOR_Purple = "\033[35m"
|
|
// COLOR_Cyan = "\033[36m"
|
|
// COLOR_Gray = "\033[37m"
|
|
// COLOR_White = "\033[97m" // Brighter white
|
|
// )
|
|
|
|
// func Log(msg string) {
|
|
// log.New(os.Stdout, msg, log.Ldate|log.Ltime)
|
|
|
|
// }
|
|
// func Colorize(colorCode string, message string) string {
|
|
// return colorCode + message + COLOR_Reset
|
|
// }
|
|
|
|
type IsStruct struct{}
|
|
|
|
var (
|
|
Is IsStruct
|
|
h = New()
|
|
)
|
|
|
|
type Helper struct {
|
|
Convert Convert
|
|
Struct Struct
|
|
Screen Screen
|
|
Error Error
|
|
If If
|
|
Log Log
|
|
}
|
|
type Convert struct {
|
|
}
|
|
type Struct struct {
|
|
}
|
|
type Screen struct {
|
|
}
|
|
type Error struct {
|
|
Val error
|
|
}
|
|
type If struct {
|
|
Error Error
|
|
}
|
|
type Log struct {
|
|
Error Error
|
|
}
|
|
|
|
func (h *Helper) P(val any) {
|
|
dump.Println(val)
|
|
}
|
|
|
|
// InsertStringValueIntoField inserts a string value into a specified field of a struct.
|
|
//
|
|
// structPtr must be a pointer to a struct.
|
|
// fieldName is the name of the field (case-sensitive).
|
|
// stringValue is the string value to be inserted.
|
|
//
|
|
// Returns an error if:
|
|
// - structPtr is not a pointer to a struct.
|
|
// - The fieldName is not found in the struct.
|
|
// - The field is not settable (e.g., unexported).
|
|
// - The field is not of type string.
|
|
func New() *Helper {
|
|
return &Helper{}
|
|
}
|
|
|
|
func (e *Error) Log() {
|
|
if e.Val != nil {
|
|
log.Println(e.Val.Error())
|
|
}
|
|
}
|
|
func (e *Error) In(err error) *Error {
|
|
e.Val = err
|
|
return e
|
|
}
|
|
func (conv *Struct) Insert(structPtr interface{}, param ...any) {
|
|
// func (conv *Struct) Insert(structPtr interface{}, fieldName string, stringValue string, sep string) string {
|
|
|
|
rawFieldName := param[0].(string)
|
|
fieldValue := param[1]
|
|
sep := ""
|
|
if len(param) > 2 {
|
|
sep = param[2].(string)
|
|
} else {
|
|
sep = "_"
|
|
}
|
|
// if len(param[2].(string)) > 0 {
|
|
// sep = param[2].(string)
|
|
// }
|
|
seperatorRune := []rune(sep)[0]
|
|
field := CapitalizeAfterChar(rawFieldName, seperatorRune)
|
|
field = CapitalizeFirstLetter(field)
|
|
field = strings.ReplaceAll(field, sep, "")
|
|
|
|
err := InsertAnyValueIntoField(structPtr, field, fieldValue)
|
|
h.Error.Val = err
|
|
h.If.Error.Log()
|
|
}
|
|
func (conv *Struct) ToStructField(str string, seperator string) string {
|
|
seperatorRune := []rune(seperator)[0]
|
|
field := CapitalizeAfterChar(str, seperatorRune)
|
|
field = CapitalizeFirstLetter(field)
|
|
field = strings.ReplaceAll(field, seperator, "")
|
|
return field
|
|
}
|
|
func InsertStringValueIntoField(structPtr interface{}, fieldName string, stringValue string) error {
|
|
if structPtr == nil {
|
|
return errors.New("structPtr cannot be nil")
|
|
}
|
|
|
|
val := reflect.ValueOf(structPtr)
|
|
if val.Kind() != reflect.Ptr {
|
|
return errors.New("structPtr must be a pointer to a struct")
|
|
}
|
|
|
|
elem := val.Elem()
|
|
if elem.Kind() != reflect.Struct {
|
|
return errors.New("structPtr must be a pointer to a struct")
|
|
}
|
|
|
|
fieldVal := elem.FieldByName(fieldName)
|
|
if !fieldVal.IsValid() {
|
|
return fmt.Errorf("field '%s' not found in struct", fieldName)
|
|
}
|
|
|
|
if !fieldVal.CanSet() {
|
|
return fmt.Errorf("field '%s' is not settable (unexported or embedded without being exported)", fieldName)
|
|
}
|
|
|
|
if fieldVal.Kind() != reflect.String {
|
|
return fmt.Errorf("field '%s' is not a string type", fieldName)
|
|
}
|
|
|
|
fieldVal.SetString(stringValue)
|
|
return nil
|
|
}
|
|
func InsertAnyValueIntoField(structPtr interface{}, fieldName string, anyValue any) error {
|
|
if structPtr == nil {
|
|
return errors.New("structPtr cannot be nil")
|
|
}
|
|
|
|
val := reflect.ValueOf(structPtr)
|
|
if val.Kind() != reflect.Ptr {
|
|
return errors.New("structPtr must be a pointer to a struct")
|
|
}
|
|
|
|
elem := val.Elem()
|
|
if elem.Kind() != reflect.Struct {
|
|
return errors.New("structPtr must be a pointer to a struct")
|
|
}
|
|
|
|
fieldVal := elem.FieldByName(fieldName)
|
|
if !fieldVal.IsValid() {
|
|
return fmt.Errorf("field '%s' not found in struct", fieldName)
|
|
}
|
|
|
|
if !fieldVal.CanSet() {
|
|
return fmt.Errorf("field '%s' is not settable (unexported or embedded without being exported)", fieldName)
|
|
}
|
|
|
|
switch v := anyValue.(type) {
|
|
case string:
|
|
{
|
|
if fieldVal.Kind() != reflect.String {
|
|
return fmt.Errorf("field '%s' is not a string type", fieldName)
|
|
}
|
|
|
|
fieldVal.SetString(v)
|
|
return nil
|
|
}
|
|
case bool:
|
|
{
|
|
if fieldVal.Kind() != reflect.Bool {
|
|
return fmt.Errorf("field '%s' is not a string type", fieldName)
|
|
}
|
|
|
|
fieldVal.SetBool(v)
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("value of field '%s' is unknown type", fieldName)
|
|
}
|
|
|
|
// CapitalizeAfterChar capitalizes the first letter immediately following each occurrence of a specific character in a string.
|
|
//
|
|
// For example:
|
|
// CapitalizeAfterChar("hello_world", '_') == "hello_World"
|
|
// CapitalizeAfterChar("this-is-a-test", '-') == "this-Is-A-Test"
|
|
// CapitalizeAfterChar(" leading spaces and_underscores", '_') == " leading spaces and_Underscores"
|
|
func CapitalizeAfterChar(input string, char rune) string {
|
|
var result strings.Builder
|
|
capitalizeNext := false // Flag to indicate if the next letter should be capitalized
|
|
|
|
for _, r := range input {
|
|
if capitalizeNext {
|
|
result.WriteRune(unicode.ToUpper(r)) // Capitalize the current rune
|
|
capitalizeNext = false // Reset the flag
|
|
} else {
|
|
result.WriteRune(r) // Write the rune as is
|
|
}
|
|
|
|
if r == char {
|
|
capitalizeNext = true // Set the flag to capitalize the next letter
|
|
}
|
|
}
|
|
return result.String()
|
|
}
|
|
|
|
func CapitalizeAfterCharMulti(input string, char rune) string {
|
|
var result strings.Builder
|
|
capitalizeNext := false // Flag to indicate if the next letter should be capitalized
|
|
|
|
for _, r := range input {
|
|
if capitalizeNext {
|
|
result.WriteRune(unicode.ToUpper(r)) // Capitalize the current rune
|
|
capitalizeNext = false // Reset the flag
|
|
} else {
|
|
result.WriteRune(r) // Write the rune as is
|
|
}
|
|
|
|
if r == char {
|
|
capitalizeNext = true // Set the flag to capitalize the next letter
|
|
}
|
|
}
|
|
return result.String()
|
|
}
|
|
|
|
func CapitalizeFirstLetter(input string) string {
|
|
if input == "" {
|
|
return input // Return empty string if input is empty
|
|
}
|
|
|
|
runes := []rune(input) // Convert string to rune slice for Unicode support
|
|
firstRune := runes[0]
|
|
|
|
if !unicode.IsLetter(firstRune) {
|
|
return input // Return original string if first char is not a letter
|
|
}
|
|
|
|
capitalizedFirstRune := unicode.ToUpper(firstRune)
|
|
runes[0] = capitalizedFirstRune
|
|
|
|
return string(runes) // Convert rune slice back to string
|
|
}
|
|
func MapIter[K string, V any](m map[K]V, fn func(K, V)) {
|
|
for p, d := range m {
|
|
fn(p, d)
|
|
}
|
|
}
|
|
func (*Screen) Clear() {
|
|
if runtime.GOOS == "windows" {
|
|
cmd := exec.Command("cmd", "/c", "cls")
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Run()
|
|
} else {
|
|
cmd := exec.Command("clear")
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Run()
|
|
}
|
|
}
|
|
|
|
func RandStringByBits(nBits int) string {
|
|
b := make([]byte, nBits/8)
|
|
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
|
return err.Error()
|
|
}
|
|
return base64.RawURLEncoding.EncodeToString(b)
|
|
}
|
|
|
|
func StructToMap(obj interface{}) map[string]any {
|
|
|
|
val := reflect.ValueOf(obj)
|
|
typ := reflect.TypeOf(obj)
|
|
result := make(map[string]any)
|
|
|
|
for i := 0; i < val.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
result[field.Name] = val.Field(i).Interface()
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func FetchGetJson(u string) (map[string]any, error) {
|
|
resp, err := http.Get(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
respByes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data := map[string]any{}
|
|
json.Unmarshal(respByes, &data)
|
|
return data, nil
|
|
}
|
|
|
|
func GetLastChar(str string) string {
|
|
return str[len(str)-1:]
|
|
}
|
|
|
|
func IsLastChar(str string, chr string) bool {
|
|
if l := GetLastChar(str); l == chr {
|
|
return true
|
|
}
|
|
return false
|
|
|
|
}
|
|
|
|
func IsLastCharDo(str string, chr string, f func(r bool)) bool {
|
|
result := IsLastChar(str, chr)
|
|
|
|
func(bool) {
|
|
f(result)
|
|
}(result)
|
|
|
|
return result
|
|
}
|
|
|
|
func IsFetchOK[V any](u string, funcName string, f func(string) (*http.Response, error)) *http.Response {
|
|
// errCntr := 0
|
|
errCntrTotal := 0
|
|
var (
|
|
a V
|
|
resp *http.Response
|
|
err error
|
|
)
|
|
for {
|
|
resp, err = f(u)
|
|
if err == nil && resp.StatusCode == 200 {
|
|
// ClearScreen()
|
|
break
|
|
} else {
|
|
// errCntr++
|
|
// errCntrTotal++
|
|
// if errCntr == 10 {
|
|
// errCntr = 0
|
|
// ClearScreen()
|
|
// }
|
|
// if errCntr == 1 {
|
|
// ClearScreen()
|
|
// }
|
|
errCntrTotalStr := strconv.Itoa(errCntrTotal)
|
|
pkg := reflect.TypeOf(a).PkgPath()
|
|
dt := time.Now()
|
|
dateTime := dt.Format("02-01-2006 15:04:05")
|
|
fmt.Println("ERROR: " + dateTime + ">---------<" + errCntrTotalStr + ">")
|
|
fmt.Println(" :")
|
|
fmt.Println(" Package name: " + pkg)
|
|
fmt.Println("Function name: " + funcName)
|
|
fmt.Println(" URL: " + u)
|
|
fmt.Println("Error message: " + err.Error())
|
|
fmt.Println("--------------------------------------")
|
|
time.Sleep(5 * time.Second)
|
|
}
|
|
|
|
}
|
|
return resp
|
|
}
|
|
|
|
func IsSliceContains[T comparable](sliceVals []T, valueToSearch T) bool {
|
|
for _, v := range sliceVals {
|
|
if v == valueToSearch {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func AddDotBetween(k ...string) string {
|
|
constructedKey := ""
|
|
for i, key := range k {
|
|
constructedKey += key
|
|
if i < len(k)-1 {
|
|
constructedKey += "."
|
|
}
|
|
}
|
|
return constructedKey
|
|
}
|
|
|
|
func RemoveSliceDuplicates(elements []string) []string {
|
|
encountered := map[string]bool{}
|
|
result := []string{}
|
|
|
|
for v := range elements {
|
|
if encountered[elements[v]] {
|
|
// Do not add duplicate.
|
|
} else {
|
|
// Record this element as an encountered element.
|
|
encountered[elements[v]] = true
|
|
// Append to result slice.
|
|
result = append(result, elements[v])
|
|
}
|
|
}
|
|
// Return the new slice.
|
|
return result
|
|
}
|
|
|
|
func IfLast[T any](counter int, someVar map[string]T, fn func()) {
|
|
counter++
|
|
if len(someVar) == counter {
|
|
fn()
|
|
}
|
|
}
|
|
|
|
func (s *IsStruct) Pointer(v any) bool {
|
|
|
|
valueOfP := reflect.ValueOf(v)
|
|
if valueOfP.Kind() == reflect.Ptr {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func AppRunner(runApp func()) {
|
|
wg := sync.WaitGroup{}
|
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
runApp()
|
|
|
|
<-ctx.Done()
|
|
//do stuff after ending
|
|
wg.Wait()
|
|
log.Println("AppRunner stopped")
|
|
os.Exit(0)
|
|
}
|
|
|
|
func StartTestHTTPServer(port int, name string) {
|
|
p := strconv.Itoa(port)
|
|
go func() {
|
|
log.Println("Test server is running at http://" + GetIP() + ":" + p)
|
|
r := mux.NewRouter()
|
|
r.Path("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, r.Host+"/ OK")
|
|
})
|
|
r.Path("/test1").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, r.Host+"/test1 OK")
|
|
})
|
|
r.Path("/test2").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
fmt.Fprintln(w, r.Host+"/test2 OK")
|
|
})
|
|
err := http.ListenAndServe(":"+p, r)
|
|
if err != nil {
|
|
log.Println(err.Error())
|
|
}
|
|
}()
|
|
}
|
|
|
|
func GetIP(prefix ...string) string {
|
|
prfx := "192.168."
|
|
if len(prefix) > 0 {
|
|
prfx = prefix[0]
|
|
}
|
|
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
fmt.Println("Error getting interface addresses:", err)
|
|
return ""
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
// Check if the address is an IP address
|
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
|
|
a := strings.HasPrefix(ipnet.IP.String(), prfx)
|
|
c := ipnet.IP.To4() != nil
|
|
if c && a { //check for ipv4
|
|
prfx = ipnet.IP.String()
|
|
break
|
|
}
|
|
// } else if ipnet.IP.To16() != nil { //check for ipv6
|
|
// fmt.Println("Local IPv6 address:", ipnet.IP.String())
|
|
// }
|
|
}
|
|
}
|
|
return prfx
|
|
}
|
|
|
|
func AppendToPointer[T any](slc *[]T, val T) {
|
|
*slc = append(*slc, val)
|
|
}
|