package utils import ( "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "net/http" "reflect" "strconv" ) func UnnamedPointer[T any](v T) *T { return &v } func GinError(c *gin.Context, code int, msg string) { c.JSON(code, gin.H{"ok": false, "msg": msg}) } func GinOk(c *gin.Context, msg string) { c.JSON(http.StatusOK, gin.H{"ok": true, "msg": msg}) } func GinOkData(c *gin.Context, data interface{}) { c.JSON(http.StatusOK, gin.H{"ok": true, "data": data}) } func GinErrorCheck(c *gin.Context, err error) bool { if err != nil { GinError(c, http.StatusBadRequest, err.Error()) return true } return false } func setValue(data string, value reflect.Value) error { switch value.Kind() { case reflect.Bool: break case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v, err := strconv.ParseInt(data, 10, 64) if err != nil { return err } value.SetInt(int64(v)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v, err := strconv.ParseUint(data, 10, 64) if err != nil { return err } value.SetUint(v) case reflect.Float32, reflect.Float64: v, err := strconv.ParseFloat(data, 64) if err != nil { return err } value.SetFloat(v) case reflect.Pointer: return setValue(data, reflect.Indirect(value)) case reflect.String: value.SetString(data) case reflect.Struct: err := json.Unmarshal([]byte(data), value.Pointer()) if err != nil { return err } default: log.Errorf("utils.setValue unsupported type %s", value.Type().Name()) return errors.New("unsupported type") } return nil } func routeWrapperHandler(handler any, names []string) func(ctx *gin.Context) { return func(c *gin.Context) { handlerFunc := reflect.ValueOf(handler) handlerFuncType := handlerFunc.Type() handlerFuncParamLen := handlerFuncType.NumIn() if handlerFuncParamLen != len(names) { panic("Handler func Param len != len(names)") } inputArgs := make([]reflect.Value, handlerFuncParamLen) for i := 0; i < handlerFuncParamLen; i += 1 { paraType := handlerFuncType.In(i) var paraValue reflect.Value if paraType.Kind() == reflect.Pointer { paraValue = reflect.New(paraType.Elem()) } else { paraValue = reflect.New(paraType) } v, ok := c.Get(names[i]) if ok { paraValue.Set(reflect.ValueOf(v)) } else { vs := c.Param(names[i]) if vs == "" { vs = c.Query(names[i]) } if vs != "" { err := setValue(vs, paraValue) if err != nil { log.WithError(err).Error("Cannot set value") continue } } else { if paraValue.Kind() == reflect.Struct || (paraType.Kind() == reflect.Pointer && paraType.Elem().Kind() == reflect.Struct) { err := c.BindJSON(paraValue.Interface()) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"ok": false, "msg": fmt.Sprintf("Cannot BindJson %s: %s", paraType.Name(), err.Error())}) return } } } } if paraType.Kind() == reflect.Pointer { inputArgs[i] = paraValue } else { inputArgs[i] = paraValue.Elem() } } out := handlerFunc.Call(inputArgs) var ret = out[0].Interface() if out[1].Interface() != nil { var err = out[1].Interface().(error) c.JSON(http.StatusInternalServerError, gin.H{"ok": false, "msg": err.Error()}) } else { c.JSON(http.StatusOK, ret) } } } func RouteWrapper(r *gin.Engine, method string, route string, handler any, names []string) { r.Handle(method, route, routeWrapperHandler(handler, names)) }