package ccxt import ( "encoding/json" "fmt" "math" "reflect" "runtime" "strconv" "strings" "sync" "time" ) func Add(a interface{}, b interface{}) interface{} { if (a == nil) || (b == nil) { return nil } switch aType := a.(type) { case int: if bType, ok := b.(int); ok { return aType + bType // Add as integers } aFloat := ToFloat64(a) bFloat := ToFloat64(b) res := aFloat + bFloat if IsInteger(res) { return ParseInt(res) } return res case int64: if bType, ok := b.(int64); ok { return aType + bType // Add as integers } aFloat := ToFloat64(a) bFloat := ToFloat64(b) res := aFloat + bFloat if IsInteger(res) { return ParseInt(res) } return res case float64: bType := ToFloat64(b) if bType == math.NaN() { return nil } res := aType + bType if IsInteger(res) { return ParseInt(res) } case string: if bType, ok := b.(string); ok { return aType + bType // Concatenate as strings } } return nil } func IsTrue(a interface{}) bool { return EvalTruthy(a) } // EvalTruthy determines if a single interface value is truthy. func EvalTruthy(val interface{}) bool { if val == nil { return false } // Check types of val switch v := val.(type) { case int, int32, int64, uint, uint32, uint64: return v != 0 case float32, float64: return v != 0.0 case string: return v != "" case bool: return v // bool is already truthy or falsy case []interface{}: return len(v) > 0 case map[string]interface{}: return len(v) > 0 case []string: return len(v) > 0 case []int64: return len(v) > 0 case []float64: return len(v) > 0 case []bool: return len(v) > 0 case []int: return len(v) > 0 default: return true // Use reflection for other complex types (slices, maps, pointers, etc.) // valType := reflect.TypeOf(val) // switch valType.Kind() { // case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Chan, reflect.Func: // return !reflect.ValueOf(val).IsNil() // } } return true // Consider non-nil complex types as truthy } // func IsInteger(value interface{}) bool { // switch value.(type) { // case int, int8, int16, int32, int64: // return true // case uint, uint8, uint16, uint32, uint64: // return true // default: // return false // } // } func IsInteger(value interface{}) bool { switch v := value.(type) { case int, int8, int16, int32, int64: return true case uint, uint8, uint16, uint32, uint64: return true case float32, float64: // Check if the float has no fractional part return v == math.Trunc(v.(float64)) default: // // Handle other numeric types, including when value is a pointer to an int type // val := reflect.ValueOf(value) // if val.Kind() == reflect.Ptr { // elem := val.Elem() // if elem.IsValid() && elem.Kind() >= reflect.Int && elem.Kind() <= reflect.Float64 { // return float64(elem.Float()) == math.Trunc(elem.Float()) // } // } return false } } func GetValue(collection interface{}, key interface{}) interface{} { if collection == nil { return nil } if key == nil { return nil } keyNum := -1 keyStr, ok := key.(string) if !ok { keyNum64 := ParseInt(key) if keyNum64 == math.MinInt64 { return nil } keyNum = int(keyNum64) } _, isMap := collection.(map[string]interface{}) if isMap || keyNum != -1 { switch v := collection.(type) { case map[string]interface{}: if !ok { return nil } if val, ok := v[keyStr]; ok { return val } return nil case []interface{}: if keyNum >= len(v) { return nil } return v[keyNum] case []string: if keyNum >= len(v) { return nil } return v[keyNum] case []int64: if keyNum >= len(v) { return nil } return v[keyNum] case []float64: if keyNum >= len(v) { return nil } return v[keyNum] case []bool: if keyNum >= len(v) { return nil } return v[keyNum] case []int: if keyNum >= len(v) { return nil } return v[keyNum] case string: if keyNum >= len(v) { return nil } return string(v[keyNum]) } } // this is needed in checkRequiredCredentials or alike reflectValue := reflect.ValueOf(collection) if reflectValue.Kind() == reflect.Ptr { reflectValue = reflectValue.Elem() } if reflectValue.Kind() == reflect.Struct { stringKey := key.(string) stringKeyCapitalized := Capitalize(stringKey) field := reflectValue.FieldByName(stringKey) fieldCapitalized := reflectValue.FieldByName(stringKeyCapitalized) if fieldCapitalized.IsValid() { return fieldCapitalized.Interface() } if field.IsValid() { return field.Interface() } return nil } switch reflectValue.Kind() { case reflect.Slice, reflect.Array: // Handle slice or array: key should be an integer index. index2 := ParseInt(key) if index2 == math.MinInt64 { return nil // Key is not an int, invalid index } index := int(index2) if index < 0 || index >= reflectValue.Len() { return nil // Index out of bounds } return reflectValue.Index(index).Interface() case reflect.Map: // Handle map: key needs to be appropriate for the map keyStr, ok := key.(string) if !ok { return nil // Key is not a string, invalid key } reflectKeyValue := reflect.ValueOf(keyStr) if reflectValue.MapIndex(reflectKeyValue).IsValid() { return reflectValue.MapIndex(reflectKeyValue).Interface() } return nil default: // Type not supported return nil } } func Multiply(a, b interface{}) interface{} { if (a == nil) || (b == nil) { return nil } aVal := reflect.ValueOf(a) bVal := reflect.ValueOf(b) // Ensure both values are numeric if !aVal.IsValid() || !bVal.IsValid() || !aVal.Type().ConvertibleTo(bVal.Type()) { return nil } // Convert a to the type of b to simplify multiplication aValConverted := aVal.Convert(bVal.Type()) // Perform multiplication based on the kind of b switch bVal.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return aValConverted.Int() * bVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: return aValConverted.Uint() * bVal.Uint() case reflect.Float32, reflect.Float64: aFloat := ToFloat64(a) bFloat := ToFloat64(b) res := aFloat * bFloat if IsInteger(res) { return ParseInt(res) } return res default: return nil } } func Divide(a, b interface{}) interface{} { if a == nil || b == nil { return nil } aVal := reflect.ValueOf(a) bVal := reflect.ValueOf(b) if !aVal.IsValid() || !bVal.IsValid() || !aVal.Type().ConvertibleTo(bVal.Type()) { return nil } aValConverted := aVal.Convert(bVal.Type()) switch bVal.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if bVal.Int() == 0 { return nil // Avoid division by zero } return aValConverted.Int() / bVal.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: if bVal.Uint() == 0 { return nil // Avoid division by zero } return aValConverted.Uint() / bVal.Uint() case reflect.Float32, reflect.Float64: aFloat := ToFloat64(a) bFloat := ToFloat64(b) if bFloat == 0.0 { return nil // Avoid division by zero } res := aFloat / bFloat if IsInteger(res) { return ParseInt(res) } return res default: return nil } } func Subtract(a, b interface{}) interface{} { if a == nil || b == nil { return nil } // aVal := reflect.ValueOf(a) // bVal := reflect.ValueOf(b) aFloat := ToFloat64(a) bFloat := ToFloat64(b) res := aFloat - bFloat if IsInteger(res) { return ParseInt(res) } return res // if !aVal.IsValid() || !bVal.IsValid() || !aVal.Type().ConvertibleTo(bVal.Type()) { // return nil // } // aValConverted := aVal.Convert(bVal.Type()) // switch bVal.Kind() { // case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: // return aValConverted.Int() - bVal.Int() // case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: // return aValConverted.Uint() - bVal.Uint() // case reflect.Float32, reflect.Float64: // aFloat := ToFloat64(a) // bFloat := ToFloat64(b) // res := aFloat - bFloat // if IsInteger(res) { // return ParseInt(res) // } // return res // default: // return nil // } } type Dict map[string]interface{} // GetArrayLength returns the length of various array or slice types or string length. func GetArrayLength(value interface{}) int { if value == nil { return 0 } switch v := value.(type) { case []interface{}: return len(v) case []string: return len(v) case []int64: return len(v) case []float64: return len(v) case []bool: return len(v) case []int: return len(v) case string: return len(v) // should we do it here? } // val := reflect.ValueOf(value) // switch val.Kind() { // case reflect.Slice, reflect.Array: // return val.Len() // case reflect.String: // return val.Len() // case reflect.Map: // // Specific check for a map type similar to List in C# // if _, ok := value.(Dict); ok { // return len(value.(Dict)) // } // } return 0 } func IsGreaterThan(a, b interface{}) bool { if a != nil && b == nil { return true } if a == nil || b == nil { return false } // Handle int, int64, float64 comparisons switch aVal := a.(type) { case int: switch bVal := b.(type) { case int: return aVal > bVal case int64: return int64(aVal) > bVal case float64: return float64(aVal) > bVal } case int64: switch bVal := b.(type) { case int: return aVal > int64(bVal) case int64: return aVal > bVal case float64: return float64(aVal) > bVal } case float64: switch bVal := b.(type) { case int: return aVal > float64(bVal) case int64: return aVal > float64(bVal) case float64: return aVal > bVal } } // If types cannot be compared, return false return false } // aVal, bVal, ok := NormalizeAndConvert(a, b) // if !ok { // return false // } // switch aVal.Kind() { // case reflect.Int, reflect.Int64: // return aVal.Int() > bVal.Int() // case reflect.Float64: // return aVal.Float() > bVal.Float() // case reflect.String: // return aVal.String() > bVal.String() // default: // return false // } // } // IsLessThan checks if a is less than b func IsLessThan(a, b interface{}) bool { return !IsGreaterThan(a, b) && !IsEqual(a, b) } // IsGreaterThanOrEqual checks if a is greater than or equal to b func IsGreaterThanOrEqual(a, b interface{}) bool { return IsGreaterThan(a, b) || IsEqual(a, b) } // IsLessThanOrEqual checks if a is less than or equal to b func IsLessThanOrEqual(a, b interface{}) bool { return IsLessThan(a, b) || IsEqual(a, b) } // Mod performs a modulus operation on a and b func Mod(a, b interface{}) interface{} { if a == nil || b == nil { return nil } aFloat := ToFloat64(a) bFloat := ToFloat64(b) if aFloat == math.NaN() || bFloat == math.NaN() { return nil } res := math.Mod(aFloat, bFloat) if IsInteger(res) { return ParseInt(res) } return res // aVal, bVal, ok := NormalizeAndConvert(a, b) // if !ok || bVal.Float() == 0 { // return nil // } // return float64(int(aVal.Float()) % int(bVal.Float())) } // IsEqual checks for equality of a and b with dynamic type support func IsEqual(a, b interface{}) bool { if a == nil && b == nil { return true } if a == nil || b == nil { return false } if (a == true && b == false) || (a == false && b == true) { return false } if (a == true && b == true) || (a == false && b == false) { return true } // // aVal, bVal, ok := NormalizeAndConvert(a, b) // if !ok { // return false // } switch aVal := a.(type) { case int: switch bVal := b.(type) { case int: return aVal == bVal case int64: return int64(aVal) == bVal case float64: return float64(aVal) == bVal } case int64: switch bVal := b.(type) { case int: return aVal == int64(bVal) case int64: return aVal == bVal case float64: return float64(aVal) == bVal } case float64: switch bVal := b.(type) { case int: return aVal == float64(bVal) case int64: return aVal == float64(bVal) case float64: return aVal == bVal } case string: if bVal, ok := b.(string); ok { return aVal == bVal } } // If types don't match or aren't handled, return false return false // switch aVal.Kind() { // case reflect.Int, reflect.Int64: // return aVal.Int() == bVal.Int() // case reflect.Float64: // return aVal.Float() == bVal.Float() // case reflect.String: // return aVal.String() == bVal.String() // default: // return false // } } // NormalizeAndConvert normalizes and attempts to convert a and b to a common type func NormalizeAndConvert(a, b interface{}) (reflect.Value, reflect.Value, bool) { aVal := reflect.ValueOf(a) bVal := reflect.ValueOf(b) if aVal.Kind() != bVal.Kind() { if aVal.Kind() < bVal.Kind() { aVal = reflect.ValueOf(ToFloat64(a)) bVal = reflect.ValueOf(ToFloat64(b)) } else { bVal = reflect.ValueOf(ToFloat64(b)) aVal = reflect.ValueOf(ToFloat64(a)) } } return aVal, bVal, true } func ToFloat64(v interface{}) float64 { var result float64 = math.NaN() val := reflect.ValueOf(v) switch val.Kind() { case reflect.Int, reflect.Int64: result = float64(val.Int()) case reflect.Float64: result = val.Float() case reflect.String: result, err := strconv.ParseFloat(val.String(), 64) if err == nil { return result } } return result } func Increment(a interface{}) interface{} { switch v := a.(type) { case int: return v + 1 case int64: return v + 1 case float64: return v + 1.0 case string: return v + "1" default: return nil } } // Decrement decreases the numeric value by 1. func Decrement(a interface{}) interface{} { switch v := a.(type) { case int: return v - 1 case int64: return v - 1 case float64: return v - 1.0 default: return nil } } // Negate negates the numeric value. func Negate(a interface{}) interface{} { switch v := a.(type) { case int: return -v case int64: return -v case float64: return -v default: return nil } } // UnaryPlus returns the numeric value unchanged. func UnaryPlus(a interface{}) interface{} { switch v := a.(type) { case int: return +v case int64: return +v case float64: return +v default: return nil } } // PlusEqual adds the value of `value` to `a`, handling some basic types. func PlusEqual(a, value interface{}) interface{} { aVal := reflect.ValueOf(a) valueVal := reflect.ValueOf(value) if aVal.Kind() != valueVal.Kind() { return nil // type mismatch } switch aVal.Kind() { case reflect.Int, reflect.Int64: return aVal.Int() + valueVal.Int() case reflect.Float64: return aVal.Float() + valueVal.Float() case reflect.String: return aVal.String() + valueVal.String() default: return nil } } // func AppendToArray(slicePtr *interface{}, element interface{}) { // array := (*slicePtr).([]interface{}) // *slicePtr = append(array, element) // } func AppendToArray(slicePtr *interface{}, element interface{}) { switch array := (*slicePtr).(type) { case []interface{}: *slicePtr = append(array, element) case []string: if strElement, ok := element.(string); ok { *slicePtr = append(array, strElement) } else { // Handle the case where the element is not a string if needed // fmt.Println("Error: element is not a string") } default: // fmt.Println("Error: Unsupported slice type") } } // without reflection func AddElementToObject(arrayOrDict interface{}, stringOrInt interface{}, value interface{}) { switch obj := arrayOrDict.(type) { case []string: if index, ok := stringOrInt.(int); ok { if index >= 0 && index < len(obj) { obj[index] = fmt.Sprintf("%v", value) // return nil } else { // return fmt.Errorf("index out of range") } } else { // return fmt.Errorf("invalid key type for slice: expected int") } case []int: if index, ok := stringOrInt.(int); ok { if index >= 0 && index < len(obj) { if v, ok := value.(int); ok { obj[index] = v // return nil } else { // return fmt.Errorf("value type mismatch for slice of int") } } else { // return fmt.Errorf("index out of range") } } else { // return fmt.Errorf("invalid key type for slice: expected int") } case []interface{}: if index, ok := stringOrInt.(int); ok { if index >= 0 && index < len(obj) { obj[index] = value // return nil } else { // return fmt.Errorf("index out of range") } } else { // return fmt.Errorf("invalid key type for slice: expected int") } case []int64: if index, ok := stringOrInt.(int); ok { if index >= 0 && index < len(obj) { if v, ok := value.(int64); ok { obj[index] = v // return nil } else { // return fmt.Errorf("value type mismatch for slice of int64") } } else { // return fmt.Errorf("index out of range") } } else { // return fmt.Errorf("invalid key type for slice: expected int") } case []float64: if index, ok := stringOrInt.(int); ok { if index >= 0 && index < len(obj) { if v, ok := value.(float64); ok { obj[index] = v // return nil } else { // return fmt.Errorf("value type mismatch for slice of float64") } } else { // return fmt.Errorf("index out of range") } } else { // return fmt.Errorf("invalid key type for slice: expected int") } case map[string]interface{}: if key, ok := stringOrInt.(string); ok { obj[key] = value // return nil } else { // return fmt.Errorf("invalid key type for map: expected string") } default: // return fmt.Errorf("unsupported type: %T", arrayOrDict) } } // func AddElementToObject(arrayOrDict interface{}, stringOrInt interface{}, value interface{}) { // val := reflect.ValueOf(arrayOrDict) // key := reflect.ValueOf(stringOrInt) // valueVal := reflect.ValueOf(value) // switch val.Kind() { // case reflect.Slice: // if key.Kind() != reflect.Int { // // return fmt.Errorf("index must be an integer for slices") // } // index := int(key.Int()) // if index < 0 || index >= val.Len() { // // return fmt.Errorf("index out of range") // } // val.Index(index).Set(valueVal) // case reflect.Map: // if !key.Type().AssignableTo(val.Type().Key()) { // // return fmt.Errorf("key type %s does not match map key type %s", key.Type(), val.Type().Key()) // } // // if !valueVal.Type().AssignableTo(val.Type().Elem()) { // // // return fmt.Errorf("value type %s does not match map value type %s", valueVal.Type(), val.Type().Elem()) // // } // // fmt.Println("key", key.Interface()) // // fmt.Println("value", valueVal.Interface()) // if !valueVal.IsValid() { // val.SetMapIndex(key, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // val.SetMapIndex(key, valueVal) // } // default: // // return fmt.Errorf("unsupported type: %s", val.Kind()) // } // // return nil // } func InOp(dict interface{}, key interface{}) bool { if dict == nil { return false } if key == nil { return false } if IsNumber(key) { return false } switch v := dict.(type) { case map[string]interface{}: if _, ok := v[key.(string)]; ok { return true } } return false // dictVal := reflect.ValueOf(dict) // // Ensure that the provided dict is a map // if dictVal.Kind() != reflect.Map { // return false // } // keyVal := reflect.ValueOf(key) // // Check if the map has the provided key todo:debug here // if dictVal.MapIndex(keyVal).IsValid() { // return true // } // return false } // func InOp(dict interface{}, key interface{}) bool { // if dict == nil { // return false // } // if key == nil { // return false // } // if IsNumber(key) { // return false // } // switch v := dict.(type) { // case map[string]interface{}: // if _, ok := v[key.(string)]; ok { // return true // } // } // return false // // dictVal := reflect.ValueOf(dict) // // // Ensure that the provided dict is a map // // if dictVal.Kind() != reflect.Map { // // return false // // } // // keyVal := reflect.ValueOf(key) // // // Check if the map has the provided key todo:debug here // // if dictVal.MapIndex(keyVal).IsValid() { // // return true // // } // // return false // } func GetIndexOf(str interface{}, target interface{}) int { switch v := str.(type) { case []string: t, ok := target.(string) if !ok { return -1 } for i, s := range v { if s == t { return i } } case []int: t, ok := target.(int) if !ok { return -1 } for i, n := range v { if n == t { return i } } case string: t, ok := target.(string) if !ok { return -1 } return strings.Index(v, t) } return -1 } // IsBool checks if the input is a boolean func IsBool(v interface{}) bool { if v == nil { return false } _, ok := v.(bool) return ok } // IsDictionary checks if the input is a map (dictionary in Python) func IsDictionary(v interface{}) bool { if v == nil { return false } switch v.(type) { case map[string]interface{}: return true case Dict: return true case map[interface{}]interface{}: return true default: return false } // return reflect.TypeOf(v).Kind() == reflect.Map } // IsString checks if the input is a string func IsString(v interface{}) bool { if v == nil { return false } _, ok := v.(string) return ok } // IsInt checks if the input is an integer func IsInt(v interface{}) bool { if v == nil { return false } switch v.(type) { case int, int8, int16, int32, int64: return true case uint, uint8, uint16, uint32, uint64: return true default: return false } } // IsFunction checks if the input is a function func IsFunction(v interface{}) bool { if v == nil { return false } return reflect.TypeOf(v).Kind() == reflect.Func } func IsNumber(v interface{}) bool { if v == nil { return false } switch v.(type) { case int, int8, int16, int32, int64: return true case uint, uint8, uint16, uint32, uint64: return true case float32, float64: return true default: return false } } func IsObject(v interface{}) bool { if v == nil { return false } kind := reflect.TypeOf(v).Kind() switch kind { case reflect.Array, reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct, reflect.UnsafePointer: return true default: return false } } func ToLower(v interface{}) string { if str, ok := v.(string); ok { return strings.ToLower(str) } return "" } // ToUpper converts a string to uppercase func ToUpper(v interface{}) string { if str, ok := v.(string); ok { return strings.ToUpper(str) } return "" } // IsInt checks if the input is an integer // func IsInt(v interface{}) bool { // switch v.(type) { // case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: // return true // default: // return false // } // } // MathFloor returns the largest integer less than or equal to the given number func MathFloor(v interface{}) float64 { if num, ok := v.(float64); ok { return math.Floor(num) } return 0 } // MathCeil returns the smallest integer greater than or equal to the given number func MathCeil(v interface{}) float64 { if num, ok := v.(float64); ok { return math.Ceil(num) } if num, ok := v.(int); ok { return math.Ceil(float64(num)) } if num, ok := v.(int64); ok { return math.Ceil(float64(num)) } return 0 } // MathRound returns the nearest integer, rounding half away from zero func MathRound(v interface{}) float64 { if num, ok := v.(float64); ok { return math.Round(num) } if num, ok := v.(int); ok { return math.Round(float64(num)) } if num, ok := v.(int64); ok { return math.Round(float64(num)) } return 0 } // StartsWith checks if the string starts with the specified prefix func StartsWith(v interface{}, prefix interface{}) bool { if str, ok := v.(string); ok { prefixStr := ToString(prefix) return strings.HasPrefix(str, prefixStr) } return false } // EndsWith checks if the string ends with the specified suffix func EndsWith(v interface{}, suffix interface{}) bool { if str, ok := v.(string); ok { suffixStr := ToString(suffix) return strings.HasSuffix(str, suffixStr) } return false } // IndexOf returns the index of the first occurrence of a substring func IndexOf(v interface{}, substr interface{}) int { if str, ok := v.(string); ok { substrStr := ToString(substr) return strings.Index(str, substrStr) } return -1 } // Trim removes leading and trailing whitespace from a string func Trim(v interface{}) string { if str, ok := v.(string); ok { return strings.TrimSpace(str) } return "" } // Contains checks if the string contains the specified substring func Contains(v interface{}, substr interface{}) bool { if str, ok := v.(string); ok { substrStr := ToString(substr) return strings.Contains(str, substrStr) } return false } func ToString(v interface{}) string { switch v := v.(type) { case string: return v case int, int8, int16, int32, int64: return fmt.Sprintf("%d", v) case uint, uint8, uint16, uint32, uint64: return fmt.Sprintf("%d", v) case float32, float64: convertedValue := ToFloat64(v) if convertedValue == math.Trunc(convertedValue) { return fmt.Sprintf("%d", int(convertedValue)) } return fmt.Sprintf("%f", v) case bool: return fmt.Sprintf("%t", v) default: // Handle maps, slices, and functions using reflection val := reflect.ValueOf(v) switch val.Kind() { case reflect.Map: result := "{" for _, key := range val.MapKeys() { result += fmt.Sprintf("%v: %v, ", ToString(key.Interface()), ToString(val.MapIndex(key).Interface())) } if len(result) > 1 { result = result[:len(result)-2] // Remove trailing comma and space } result += "}" return result case reflect.Slice, reflect.Array: result := "[" for i := 0; i < val.Len(); i++ { result += fmt.Sprintf("%v, ", ToString(val.Index(i).Interface())) } if len(result) > 1 { result = result[:len(result)-2] // Remove trailing comma and space } result += "]" return result case reflect.Func: return fmt.Sprintf("Function: %v", val.Type().String()) default: return fmt.Sprintf("%v", v) } } } func Join(slice interface{}, sep interface{}) string { sepStr := ToString(sep) var strSlice []string switch v := slice.(type) { case []string: strSlice = v case []interface{}: for _, elem := range v { strSlice = append(strSlice, ToString(elem)) } default: return "" } return strings.Join(strSlice, sepStr) } // Split splits a string into a slice of substrings separated by a separator func Split(str interface{}, sep interface{}) []string { strVal, ok := str.(string) if !ok { return nil } sepStr := ToString(sep) return strings.Split(strVal, sepStr) } // ObjectKeys returns the keys of a map as a slice of strings func ObjectKeys(v interface{}) []string { if v == nil { return nil } if mapObject, ok := v.(map[string]interface{}); ok { keys := make([]string, 0, len(mapObject)) for key := range mapObject { keys = append(keys, key) } return keys } return nil // val := reflect.ValueOf(v) // if val.Kind() != reflect.Map { // return nil // } // keys := val.MapKeys() // strKeys := make([]string, len(keys)) // for i, key := range keys { // strKeys[i] = ToString(key.Interface()) // } // return strKeys } // ObjectValues returns the values of a map as a slice of interface{} func ObjectValues(v interface{}) []interface{} { // return values if mapObject, ok := v.(map[string]interface{}); ok { values := make([]interface{}, 0, len(mapObject)) for _, value := range mapObject { values = append(values, value) } return values } return nil // val := ref } func JsonParse(jsonStr2 interface{}) interface{} { jsonStr := jsonStr2.(string) var result interface{} err := json.Unmarshal([]byte(jsonStr), &result) if err != nil { return nil } return result } func IsArray(v interface{}) bool { if v == nil { return false } switch v.(type) { case []interface{}: return true case []string, []bool: return true case []int, []int8, []int16, []int32, []int64, []float32, []float64, []uint, []uint8, []uint16, []uint32, []uint64: return true default: return false // kind := reflect.TypeOf(v).Kind() // return kind == reflect.Slice || kind == reflect.Array } } func Shift(slice interface{}) (interface{}, interface{}) { sliceVal, ok := castToSlice(slice) if !ok || len(sliceVal) == 0 { return slice, nil } return sliceVal[1:], sliceVal[0] } // Reverse reverses the elements of a slice in place func Reverse(slice interface{}) { sliceVal, ok := castToSlice(slice) if !ok { panic("provided value is not a slice") } // Reverse the elements in place for i, j := 0, len(sliceVal)-1; i < j; i, j = i+1, j-1 { sliceVal[i], sliceVal[j] = sliceVal[j], sliceVal[i] } // Copy the reversed values back into the original slice // Since Go is a pass-by-value language, we need to reflect to modify the original slice in place v := reflect.ValueOf(slice) for i := 0; i < v.Len(); i++ { v.Index(i).Set(reflect.ValueOf(sliceVal[i])) } } // Pop removes the last element from a slice and returns the new slice and the removed element func Pop(slice interface{}) (interface{}, interface{}) { sliceVal, ok := castToSlice(slice) if !ok || len(sliceVal) == 0 { return slice, nil } return sliceVal[:len(sliceVal)-1], sliceVal[len(sliceVal)-1] } func CastToSlice(slice interface{}) ([]interface{}, bool) { return castToSlice(slice) } // Helper function to cast interface{} to []interface{} func castToSlice(slice interface{}) ([]interface{}, bool) { val := reflect.ValueOf(slice) if val.Kind() != reflect.Slice { return nil, false } sliceVal := make([]interface{}, val.Len()) for i := 0; i < val.Len(); i++ { sliceVal[i] = val.Index(i).Interface() } return sliceVal, true } func Replace(input interface{}, old interface{}, new interface{}) string { str := ToString(input) oldStr := ToString(old) newStr := ToString(new) return strings.ReplaceAll(str, oldStr, newStr) } // PadEnd pads the input string on the right with padStr until it reaches the specified length func PadEnd(input interface{}, length2 interface{}, padStr interface{}) string { length := int(ParseInt(length2)) str := ToString(input) pad := ToString(padStr) for len(str) < length { str += pad } return str[:length] } // PadStart pads the input string on the left with padStr until it reaches the specified length func PadStart(input interface{}, length2 interface{}, padStr interface{}) string { length := int(ParseInt(length2)) str := ToString(input) pad := ToString(padStr) for len(str) < length { str = pad + str } return str[len(str)-length:] } // DateNow returns the current date and time as a string func DateNow() string { return time.Now().Format(time.RFC3339) } func GetLength(v interface{}) int { val := reflect.ValueOf(v) switch val.Kind() { case reflect.String: return len(val.String()) case reflect.Array, reflect.Slice: return val.Len() default: return 0 } } func IsNil(x interface{}) bool { // https://blog.devtrovert.com/p/go-secret-interface-nil-is-not-nil if x == nil { return true } return false // switch val := x.(type){ // case interface{}: // return val == nil // case // } // value := reflect.ValueOf(x) // kind := value.Kind() // switch kind { // case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: // return value.IsNil() // default: // return false // } } func GetArg(v []interface{}, index int, def interface{}) interface{} { if len(v) <= index { return def } val := v[index] if val == nil { return def } if res, ok := val.([]interface{}); ok { // this is not working well with safeList(x, 'key', []) but works for fetchTrade(s, options interface{}...) // if len(res) == 0 { // return def // } if res == nil { return def } } // do we need this?? // if IsNil(val) { // check https://blog.devtrovert.com/p/go-secret-interface-nil-is-not-nil // return def // } return val } func Ternary(cond bool, whenTrue interface{}, whenFalse interface{}) interface{} { if cond { return whenTrue } return whenFalse } func IsInstance(value interface{}, typ interface{}) bool { // Get the reflect.Type of the value and the type if s, ok := value.(string); ok { isError := strings.HasPrefix(s, "panic") if isError { value := reflect.ValueOf(typ) funcName := "" if value.Kind() == reflect.Func { funcName = runtime.FuncForPC(value.Pointer()).Name() // Extract only the function name by removing the package path parts := strings.Split(funcName, ".") funcName = parts[len(parts)-1] } return strings.Contains(s, funcName) } } valueType := reflect.TypeOf(value) typeType := reflect.TypeOf(typ) // Compare the two types return valueType == typeType } func Slice(str2 interface{}, idx1 interface{}, idx2 interface{}) string { if str2 == nil { return "" } str := str2.(string) var start int64 = -1 if idx1 != nil { start = ParseInt(idx1) } var lenStr int64 = int64(len(str)) if idx2 == nil { if start < 0 { innerStart := lenStr + start if innerStart < 0 { innerStart = 0 } return str[innerStart:] } return str[start:] } else { end := ParseInt(idx2) if start < 0 { start = lenStr + start } if end < 0 { end = lenStr + end } if end > lenStr { end = lenStr } return str[start:end] } } type Task func() interface{} func PromiseAll(tasksInterface interface{}) <-chan interface{} { return promiseAll(tasksInterface) } func promiseAll(tasksInterface interface{}) <-chan interface{} { ch := make(chan interface{}) panicChan := make(chan interface{}, 1) // Separate channel for panics var once sync.Once // Ensure only one message is sent to ch go func() { defer close(ch) defer ReturnPanicError(ch) // Ensure tasksInterface is a slice of channels (<-chan interface{}) tasks, ok := tasksInterface.([]interface{}) if !ok { ch <- nil // Return nil if the input is not a slice of interfaces return } results := make([]interface{}, len(tasks)) var wg sync.WaitGroup var resultsLock sync.Mutex wg.Add(len(tasks)) for i, task := range tasks { go func(i int, task interface{}) { defer wg.Done() // Capture panic and send to panicChan directly defer func() { if r := recover(); r != nil { if r != "break" { once.Do(func() { ch <- "panic:" + ToString(r) }) } } }() // Assert the task is a channel if chanTask, ok := task.(<-chan interface{}); ok { // Receive the result from the channel result := <-chanTask resultsLock.Lock() results[i] = result resultsLock.Unlock() } else { // If the task is not a channel, set the result to nil resultsLock.Lock() results[i] = nil resultsLock.Unlock() } }(i, task) } // Wait for all tasks to complete wg.Wait() close(panicChan) // If no panics occurred, send the results once.Do(func() { ch <- results }) }() return ch } // func promiseAll(tasksInterface interface{}) <-chan interface{} { // ch := make(chan interface{}) // panicChan := make(chan interface{}, 1) // Separate channel for panics // go func() { // defer close(ch) // // Ensure tasksInterface is a slice of channels (<-chan interface{}) // tasks, ok := tasksInterface.([]interface{}) // if !ok { // ch <- nil // Return nil if the input is not a slice of interfaces // return // } // results := make([]interface{}, len(tasks)) // var wg sync.WaitGroup // wg.Add(len(tasks)) // for i, task := range tasks { // go func(i int, task interface{}) { // defer wg.Done() // defer ReturnPanicError(panicChan) // // Assert the task is a channel // if chanTask, ok := task.(<-chan interface{}); ok { // // Receive the result from the channel // results[i] = <-chanTask // } else { // // If the task is not a channel, set the result to nil // results[i] = nil // } // }(i, task) // } // // Wait for all tasks to complete // wg.Wait() // close(panicChan) // // Check if any panics occurred and report the first one // select { // case panicMsg := <-panicChan: // ch <- panicMsg // Send the panic message // default: // ch <- results // No panics, send results // } // }() // return ch // } // func promiseAll(tasksInterface interface{}) <-chan interface{} { // ch := make(chan interface{}) // go func() { // defer close(ch) // defer func() { // if r := recover(); r != nil { // if r != "break" { // ch <- "panic:" + ToString(r) // } // } // }() // // Ensure tasksInterface is a slice of channels (<-chan interface{}) // tasks, ok := tasksInterface.([]interface{}) // if !ok { // ch <- nil // Return nil if the input is not a slice of interfaces // return // } // results := make([]interface{}, len(tasks)) // var wg sync.WaitGroup // wg.Add(len(tasks)) // // A separate channel to capture panics // panicChan := make(chan string, len(tasks)) // for i, task := range tasks { // go func(i int, task interface{}) { // defer wg.Done() // defer func() { // if r := recover(); r != nil { // if r != "break" { // panicChan <- "panic:" + ToString(r) // } // } // }() // // Assert the task is a channel // if chanTask, ok := task.(<-chan interface{}); ok { // // Receive the result from the channel // results[i] = <-chanTask // } else { // // If the task is not a channel, set the result to nil // results[i] = nil // } // }(i, task) // } // // Wait for all tasks to complete // wg.Wait() // close(panicChan) // // Check if any panics occurred and report the first one // select { // case panicMsg := <-panicChan: // ch <- panicMsg // Send the panic message // default: // ch <- results // No panics, send results // } // }() // return ch // } // func promiseAll(tasksInterface interface{}) <-chan interface{} { // ch := make(chan interface{}) // go func() { // defer close(ch) // defer func() { // if r := recover(); r != nil { // if r != "break" { // ch <- "panic:" + ToString(r) // } // } // }() // // Ensure tasksInterface is a slice of channels (<-chan interface{}) // tasks, ok := tasksInterface.([]interface{}) // if !ok { // ch <- nil // Return nil if the input is not a slice of interfaces // return // } // results := make([]interface{}, len(tasks)) // var wg sync.WaitGroup // wg.Add(len(tasks)) // for i, task := range tasks { // go func(i int, task interface{}) { // defer wg.Done() // defer func() { // if r := recover(); r != nil { // if r != "break" { // ch <- "panic:" + ToString(r) // } // } // }() // // Assert the task is a channel // if chanTask, ok := task.(<-chan interface{}); ok { // // Receive the result from the channel // results[i] = <-chanTask // } else { // // If the task is not a channel, set the result to nil // results[i] = nil // } // }(i, task) // } // // Wait for all tasks to complete // wg.Wait() // // Once all tasks are done, send the results // ch <- results // }() // return ch // } func ParseInt(number interface{}) int64 { switch v := number.(type) { case int: return int64(v) case int8: return int64(v) case int16: return int64(v) case int32: return int64(v) case int64: return v case uint: return int64(v) case uint8: return int64(v) case uint16: return int64(v) case uint32: return int64(v) // case uint64: // if v <= uint64(^int64(0)) { // return int64(v) // } case float32: return int64(v) case float64: return int64(v) case string: if i, err := strconv.ParseInt(v, 10, 64); err == nil { return i } } return math.MinInt64 // Default value if conversion is not possible } func MathMin(a, b interface{}) interface{} { return mathMin(a, b) } func mathMin(a, b interface{}) interface{} { if a == nil || b == nil { return nil } af := ToFloat64(a) bf := ToFloat64(b) if af == math.NaN() || bf == math.NaN() { return nil } if af < bf { return af } return bf // switch a := a.(type) { // case int: // b := b.(int) // if a < b { // return a // } // return b // case float64: // b := b.(float64) // if a < b { // return a // } // return b // case string: // b := b.(string) // if a < b { // return a // } // return b // default: // return nil // } } func MathMax(a, b interface{}) interface{} { return mathMax(a, b) } // mathMax returns the maximum of two values of the same type. // It supports int, float64, and string types. func mathMax(a, b interface{}) interface{} { if a == nil || b == nil { return nil } af := ToFloat64(a) bf := ToFloat64(b) if af == math.NaN() || bf == math.NaN() { return nil } if af > bf { return af } return bf } // parseInt tries to convert various types of input to an int // func parseInt(input interface{}) interface{} { // switch v := input.(type) { // case int: // return v // case int8: // return int(v) // case int16: // return int(v) // case int32: // return int(v) // case int64: // return int(v) // case uint: // return int(v) // case uint8: // return int(v) // case uint16: // return int(v) // case uint32: // return int(v) // case uint64: // return int(v) // case float32: // return int(v) // case float64: // return int(v) // case string: // if result, err := strconv.Atoi(v); err == nil { // return result // } // return nil // default: // return nil // } // } // parseFloat tries to convert various types of input to a float64 func ParseFloat(input interface{}) interface{} { switch v := input.(type) { case float32: return float64(v) case float64: return v case int: return float64(v) case int8: return float64(v) case int16: return float64(v) case int32: return float64(v) case int64: return float64(v) case uint: return float64(v) case uint8: return float64(v) case uint16: return float64(v) case uint32: return float64(v) case uint64: return float64(v) case string: if result, err := strconv.ParseFloat(v, 64); err == nil { return result } return nil default: return nil } } func ParseJSON(input interface{}) interface{} { jsonString, ok := input.(string) if !ok { return nil } // // var result interface{} // if jsonString[0] == '[' { // var arrayResult []map[string]interface{} // err := json.Unmarshal([]byte(jsonString), &arrayResult) // if err != nil { // return nil // } // return arrayResult // } // var mapResult map[string]interface{} // err := json.Unmarshal([]byte(jsonString), &mapResult) // if err != nil { // return nil // } // return mapResult var result interface{} decoder := json.NewDecoder(strings.NewReader(jsonString)) decoder.UseNumber() // Ensures large numbers are handled correctly err := decoder.Decode(&result) if err != nil { return nil } convertNumbers(result) //convert json.Number to int64 return result } func convertNumbers(data interface{}) { switch v := data.(type) { case map[string]interface{}: for key, value := range v { if number, ok := value.(json.Number); ok { // Try to convert the json.Number to int64 if intVal, err := number.Int64(); err == nil { v[key] = intVal } else { v[key] = number.String() // Preserve the string if not convertible to int64 } } else { convertNumbers(value) // Recurse for nested maps } } case []interface{}: for i, value := range v { if number, ok := value.(json.Number); ok { // Try to convert the json.Number to int64 if intVal, err := number.Int64(); err == nil { v[i] = intVal } else { v[i] = number.String() // Preserve the string if not convertible to int64 } } else { convertNumbers(value) // Recurse for nested arrays } } } } func throwDynamicException(exceptionType interface{}, message interface{}) { functionError := exceptionType.(func(...interface{}) error) errorMsg := functionError(message) panic(errorMsg) // to do implement // // exceptionTypeStr, ok := exceptionType.(string) // if !ok { // panic("exceptionType must be a string representing the error type") // // messageStr, ok := message.(string) // // if !ok { // // panic("message must be a string") // // } // // constructor, exists := customErrors[exceptionTypeStr] // // if !exists { // // panic(errors.New("unknown error type: " + exceptionTypeStr)) // // } // // err := constructor(messageStr) // // panic(err) } func OpNeg(value interface{}) interface{} { val := reflect.ValueOf(value) switch val.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return -val.Int() case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return nil // Cannot negate unsigned integers, return nil case reflect.Float32, reflect.Float64: return -val.Float() case reflect.Complex64, reflect.Complex128: return -val.Complex() default: return nil // Unsupported type, return nil } } func JsonStringify(obj interface{}) string { if obj == nil { return "" } // Check if the object is an error (Go's equivalent of an exception) if err, ok := obj.(error); ok { // Create an anonymous struct with the error type name errorObj := struct { Name string `json:"name"` }{ Name: reflect.TypeOf(err).Name(), } // Serialize the error object to JSON jsonData, _ := json.Marshal(errorObj) return string(jsonData) } // Serialize the object to JSON jsonData, _ := json.Marshal(obj) return string(jsonData) } func toFixed(number interface{}, decimals interface{}) float64 { // Assert that the number is a float64 or convert it num := ToFloat64(number) // Assert that the decimals is an int or convert it dec := ParseInt(decimals) // Calculate the rounding multiplier multiplier := math.Pow(10, float64(dec)) return math.Round(num*multiplier) / multiplier } func Remove(dict interface{}, key interface{}) { // Attempt to cast the dict to map[string]interface{} castedDict, ok := dict.(map[string]interface{}) if !ok { // Panic if the cast fails panic("provided value is not a map[string]interface{}") } // Attempt to cast the key to string keyStr, ok := key.(string) if !ok { // Panic if the key is not a string panic("provided key is not a string") } // Check if the key exists, panic if it doesn't if _, exists := castedDict[keyStr]; !exists { panic(fmt.Sprintf("key '%s' does not exist in the map", keyStr)) } // Remove the key from the map delete(castedDict, keyStr) } func Capitalize(s string) string { if len(s) == 0 { return s } // Convert the first letter to uppercase firstLetter := strings.ToUpper(string(s[0])) // Combine the uppercase first letter with the rest of the string return firstLetter + s[1:] } func SetDefaults(p interface{}) { setDefaults(p) } func setDefaults(p interface{}) { // Get the value of the pointer to struct val := reflect.ValueOf(p).Elem() typ := val.Type() // Iterate over the fields of the struct using reflection for i := 0; i < val.NumField(); i++ { field := val.Field(i) fieldType := typ.Field(i) if value, ok := fieldType.Tag.Lookup("default"); ok { switch field.Kind() { case reflect.String: if field.String() == "" { field.SetString(value) } case reflect.Int: if field.Int() == 0 { if intValue, err := strconv.Atoi(value); err == nil { field.SetInt(int64(intValue)) } } // Add other types as necessary } } } } // func CallInternalMethod(itf interface{}, name2 string, args ...interface{}) <-chan interface{} { // name := Capitalize(name2) // baseValue := reflect.ValueOf(itf) // baseType := baseValue.Type() // ch := make(chan interface{}) // go func() { // // Error handling // defer func() { // if r := recover(); r != nil { // ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) // close(ch) // } // }() // for i := 0; i < baseType.NumMethod(); i++ { // method := baseType.Method(i) // if name == method.Name { // methodValue := baseValue.MethodByName(name) // methodType := method.Type // numIn := methodType.NumIn() // isVariadic := methodType.IsVariadic() // var in []reflect.Value // // Handle fixed arguments for both regular and variadic functions // for k := 0; k < numIn-1; k++ { // if k < len(args) { // if args[k] == nil { // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } else { // // paramType := methodType.In(k) // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // // in = append(in, reflect.Zero(paramType)) // } // } // // Properly handle the variadic arguments // if isVariadic { // variadicArgs := []reflect.Value{} // // variadicType := methodType.In(numIn - 1).Elem() // Get the type of the variadic argument // for k := numIn - 1; k < len(args); k++ { // if args[k] == nil { // variadicArgs = append(variadicArgs, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // variadicArgs = append(variadicArgs, reflect.ValueOf(args[k])) // } // } // in = append(in, variadicArgs...) // } else if len(args) >= numIn-1 { // // Handle non-variadic arguments beyond fixed ones // for k := numIn - 1; k < len(args); k++ { // if args[k] == nil { // // paramType := methodType.In(k) // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } // } // // Call the method with the constructed arguments // res := methodValue.Call(in) // // Handle the result // if len(res) > 0 && res[0].Kind() == reflect.Chan { // resultChan := res[0] // go func() { // for { // val, ok := resultChan.Recv() // if !ok { // break // result channel is closed // } // ch <- val.Interface() // pass the value to the output channel // } // close(ch) // close the output channel after all values are received // }() // return // } else if len(res) > 0 { // ch <- res[0].Interface() // } else { // ch <- nil // } // close(ch) // return // } // } // // If no method is found, return nil // ch <- nil // close(ch) // }() // return ch // } // var methodCache = sync.Map{} // func CallInternalMethodCache(itf interface{}, name2 string, args ...interface{}) <-chan interface{} { // name := Capitalize(name2) // baseValue := reflect.ValueOf(itf) // baseType := baseValue.Type() // // Cache key to avoid redundant reflection // cacheKey := fmt.Sprintf("%T.%s", itf, name) // cachedMethod, found := methodCache.Load(cacheKey) // ch := make(chan interface{}) // go func() { // defer func() { // if r := recover(); r != nil { // ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) // } // close(ch) // }() // var method reflect.Method // if found { // method = cachedMethod.(reflect.Method) // } else { // for i := 0; i < baseType.NumMethod(); i++ { // if baseType.Method(i).Name == name { // method = baseType.Method(i) // methodCache.Store(cacheKey, method) // break // } // } // if method.Name == "" { // ch <- nil // return // } // } // methodValue := baseValue.MethodByName(name) // methodType := method.Type // numIn := methodType.NumIn() // // isVariadic := methodType.IsVariadic() // in := make([]reflect.Value, 0, numIn) // // Handle arguments // for k := 0; k < numIn; k++ { // if k < len(args) { // if args[k] == nil { // in = append(in, reflect.Zero(methodType.In(k))) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } else { // in = append(in, reflect.Zero(methodType.In(k))) // } // } // // Call method // res := methodValue.Call(in) // // Return result // if len(res) > 0 { // ch <- res[0].Interface() // } else { // ch <- nil // } // }() // return ch // } // original imp func CallInternalMethod3(itf interface{}, name2 string, args ...interface{}) <-chan interface{} { name := Capitalize(name2) baseValue := reflect.ValueOf(itf) baseType := baseValue.Type() ch := make(chan interface{}) go func() { // Error handling defer func() { if r := recover(); r != nil { ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) close(ch) } }() for i := 0; i < baseType.NumMethod(); i++ { method := baseType.Method(i) if name == method.Name { methodValue := baseValue.MethodByName(name) methodType := method.Type numIn := methodType.NumIn() isVariadic := methodType.IsVariadic() var in []reflect.Value // Handle fixed arguments for both regular and variadic functions for k := 0; k < numIn-1; k++ { if k < len(args) { if args[k] == nil { in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) } else { in = append(in, reflect.ValueOf(args[k])) } } else { // paramType := methodType.In(k) in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // in = append(in, reflect.Zero(paramType)) } } // Properly handle the variadic arguments if isVariadic { variadicArgs := []reflect.Value{} // variadicType := methodType.In(numIn - 1).Elem() // Get the type of the variadic argument for k := numIn - 1; k < len(args); k++ { if args[k] == nil { variadicArgs = append(variadicArgs, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) } else { variadicArgs = append(variadicArgs, reflect.ValueOf(args[k])) } } in = append(in, variadicArgs...) } else if len(args) >= numIn-1 { // Handle non-variadic arguments beyond fixed ones for k := numIn - 1; k < len(args); k++ { if args[k] == nil { // paramType := methodType.In(k) in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) } else { in = append(in, reflect.ValueOf(args[k])) } } } // Call the method with the constructed arguments res := methodValue.Call(in) // Handle the result if len(res) > 0 && res[0].Kind() == reflect.Chan { resultChan := res[0] go func() { for { val, ok := resultChan.Recv() if !ok { break // result channel is closed } ch <- val.Interface() // pass the value to the output channel } close(ch) // close the output channel after all values are received }() return } else if len(res) > 0 { ch <- res[0].Interface() } else { ch <- nil } close(ch) return } } // If no method is found, return nil ch <- nil close(ch) }() return ch } func CallInternalMethod(methodCache *sync.Map, itf interface{}, name2 string, args ...interface{}) <-chan interface{} { name := Capitalize(name2) // baseValue := reflect.ValueOf(itf) // baseType := baseValue.Type() // if !this.cacheLoaded { // this.cacheLoaded = true // this.WarmUpCache() // } ch := make(chan interface{}) go func() { // Error handling defer func() { if r := recover(); r != nil { ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) close(ch) } }() cacheKey := fmt.Sprintf("%s", name) cachedMethod, found := methodCache.Load(cacheKey) if !found { panic(name + " :method not found") } cachedMap := cachedMethod.(map[string]interface{}) // var method reflect.Method // for i := 0; i < baseType.NumMethod(); i++ { // method = baseType.Method(i) // if name == method.Name { // break // } // } // method := cachedMap["method"].(reflect.Method) methodValue := cachedMap["methodValue"].(reflect.Value) methodType := cachedMap["methodType"].(reflect.Type) numIn := cachedMap["numIn"].(int) isVariadic := cachedMap["isVariadic"].(bool) var in []reflect.Value // Fixed argument handling for both regular and variadic functions for k := 0; k < numIn-1; k++ { if k < len(args) { if args[k] == nil { paramType := methodType.In(k + 1) // Account for receiver not being part of args in = append(in, reflect.Zero(paramType)) } else { in = append(in, reflect.ValueOf(args[k])) } } else { paramType := methodType.In(k + 1) // Account for receiver not being part of args in = append(in, reflect.Zero(paramType)) } } if isVariadic && len(args) >= numIn-1 { variadicType := methodType.In(numIn - 1).Elem() // Get the type of the variadic argument for k := numIn - 1; k < len(args); k++ { if args[k] == nil { in = append(in, reflect.Zero(variadicType)) } else { in = append(in, reflect.ValueOf(args[k])) } } } // Call the method with the constructed arguments res := methodValue.Call(in) // Handle the result if len(res) > 0 && res[0].Kind() == reflect.Chan { resultChan := res[0] go func() { for { val, ok := resultChan.Recv() if !ok { break // result channel is closed } ch <- val.Interface() // pass the value to the output channel } close(ch) // close the output channel after all values are received }() return } else if len(res) > 0 { ch <- res[0].Interface() } else { ch <- nil } ch <- nil close(ch) }() return ch } // func CallInternalMethod(itf interface{}, name2 string, args ...interface{}) <-chan interface{} { // name := Capitalize(name2) // baseValue := reflect.ValueOf(itf) // baseType := baseValue.Type() // ch := make(chan interface{}) // go func() { // // Error handling // defer func() { // if r := recover(); r != nil { // ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) // close(ch) // } // }() // for i := 0; i < baseType.NumMethod(); i++ { // method := baseType.Method(i) // if name == method.Name { // methodValue := baseValue.MethodByName(name) // methodType := method.Type // numIn := methodType.NumIn() // isVariadic := methodType.IsVariadic() // var in []reflect.Value // // Fixed argument handling for both regular and variadic functions // for k := 0; k < numIn-1; k++ { // if k < len(args) { // if args[k] == nil { // paramType := methodType.In(k) // in = append(in, reflect.Zero(paramType)) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } else { // paramType := methodType.In(k) // in = append(in, reflect.Zero(paramType)) // } // } // // Handle the variadic arguments // if isVariadic && len(args) >= numIn-1 { // variadicType := methodType.In(numIn - 1).Elem() // Get the type of the variadic argument // for k := numIn - 1; k < len(args); k++ { // if args[k] == nil { // in = append(in, reflect.Zero(variadicType)) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } // } else if len(args) >= numIn-1 { // // Handle non-variadic arguments beyond fixed ones // for k := numIn - 1; k < len(args); k++ { // if args[k] == nil { // paramType := methodType.In(k) // in = append(in, reflect.Zero(paramType)) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } // } // // Call the method with the constructed arguments // res := methodValue.Call(in) // // Handle the result // if len(res) > 0 && res[0].Kind() == reflect.Chan { // resultChan := res[0] // go func() { // for { // val, ok := resultChan.Recv() // if !ok { // break // result channel is closed // } // ch <- val.Interface() // pass the value to the output channel // } // close(ch) // close the output channel after all values are received // }() // return // } else if len(res) > 0 { // ch <- res[0].Interface() // } else { // ch <- nil // } // close(ch) // return // } // } // // If no method is found, return nil // ch <- nil // close(ch) // }() // return ch // } // original version not working for createExpiredEtc.. // func CallInternalMethod(itf interface{}, name2 string, args ...interface{}) <-chan interface{} { // name := Capitalize(name2) // baseType := reflect.TypeOf(itf) // ch := make(chan interface{}) // go func() { // // error handling // defer func() { // if r := recover(); r != nil { // // panic(r) // ch <- fmt.Sprintf("panic:%v:%v:%v", getCallerName(), name2, r) // } // }() // for i := 0; i < baseType.NumMethod(); i++ { // method := baseType.Method(i) // if name == method.Name { // methodType := method.Type // numIn := methodType.NumIn() // isVariadic := methodType.IsVariadic() // var in []reflect.Value // if isVariadic { // // Handle fixed arguments // for k := 0; k < numIn-1; k++ { // if k < len(args) { // if args[k] == nil { // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } else { // // paramType := methodType.In(k) // // in = append(in, reflect.Zero(paramType)) // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } // } // // Handle variadic arguments // // variadicType := methodType.In(numIn - 1).Elem() // for k := numIn - 1; k < len(args); k++ { // if args[k] == nil { // in = append(in, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } // } else { // for k := 0; k < numIn; k++ { // if k < len(args) { // if args[k] == nil { // paramType := methodType.In(k) // in = append(in, reflect.Zero(paramType)) // } else { // in = append(in, reflect.ValueOf(args[k])) // } // } else { // paramType := methodType.In(k) // in = append(in, reflect.Zero(paramType)) // } // } // } // // Call the method // res := reflect.ValueOf(itf).MethodByName(name).Call(in) // // Check if the result is a channel // if len(res) > 0 && res[0].Kind() == reflect.Chan { // resultChan := res[0] // // Read values from the returned channel and pass them to ch // go func() { // for { // val, ok := resultChan.Recv() // if !ok { // break // result channel is closed // } // valInt := val.Interface() // ch <- valInt // pass the value to the output channel // } // close(ch) // close the output channel after all values are received // }() // // // Don't close `ch` yet, as it will be closed after the resultChan is read // return // } else if len(res) > 0 { // // Directly return the first result if it's not a channel // val := res[0].Interface() // ch <- val // } else { // // Return nil if no results // ch <- nil // } // close(ch) // return // } // } // // If no method is found, return nil // ch <- nil // close(ch) // }() // return ch // } func PanicOnError(msg interface{}) { caller := getCallerName() switch v := msg.(type) { case string: if strings.HasPrefix(v, "panic:") { panic(fmt.Sprintf("panic:%v:%v", caller, msg)) // panic(v) } case []interface{}: for _, item := range v { if str, ok := item.(string); ok && strings.HasPrefix(str, "panic:") { // panic(fmt.Sprintf("panic:%v:%v", caller, str)) panic(str) } else if nestedSlice, ok := item.([]interface{}); ok { // Handle nested []interface{} cases recursively PanicOnError(nestedSlice) } } default: return } } func ReturnPanicError(ch chan interface{}) { // https://stackoverflow.com/questions/72651899/why-golang-can-not-recover-from-a-panic-in-a-function-called-by-the-defer-functi if r := recover(); r != nil { if r != "break" { strErr := ToString(r) if !strings.HasPrefix(strErr, "panic:") { ch <- "panic:" + strErr } else { ch <- strErr } } } } func GetCallerName() string { return getCallerName() } func getCallerName() string { // Skip 2 levels to get the name of the caller of the function that called this one pc, _, _, ok := runtime.Caller(3) if !ok { return "Unknown" } fn := runtime.FuncForPC(pc) if fn == nil { return "Unknown" } return fn.Name() } func Print(v interface{}) { fmt.Println(v) }