wmj-test/src/utils/utils.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))
}