diff --git a/src/utils/utils.go b/src/utils/utils.go index c9238ef..4d0cabc 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -1,8 +1,14 @@ 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 { @@ -28,3 +34,104 @@ func GinErrorCheck(c *gin.Context, err error) bool { } 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)) +} diff --git a/test/test_wrapper.go b/test/test_wrapper.go new file mode 100644 index 0000000..422922c --- /dev/null +++ b/test/test_wrapper.go @@ -0,0 +1,25 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/gin-gonic/gin" + "k8s-manager/src/model" + "k8s-manager/src/utils" +) + +func DataHandler(model model.DataModel, q1 string, q2 int) (map[string]any, error) { + s, _ := json.Marshal(model) + fmt.Println(string(s)) + fmt.Printf("Call DataHandler %s %d\n", q1, q2) + return gin.H{"name": model.Name}, nil +} + +func main() { + r := gin.Default() + utils.RouteWrapper(r, "GET", "/index", DataHandler, []string{"model", "q1", "q2"}) + err := r.Run(":9000") + if err != nil { + fmt.Println(err) + } +}