138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
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))
|
|
}
|