|
|
@@ -0,0 +1,277 @@
|
|
|
+package cache
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "git.sxidc.com/go-tools/utils/reflectutils"
|
|
|
+ "git.sxidc.com/go-tools/utils/strutils"
|
|
|
+ "github.com/pkg/errors"
|
|
|
+ "reflect"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type Cache interface {
|
|
|
+ Set(key string, value string) error
|
|
|
+ Get(key string) (string, error)
|
|
|
+ GetMulti(keys []string) (map[string]string, error)
|
|
|
+ GetAll() (map[string]string, error)
|
|
|
+ Delete(key string) error
|
|
|
+ Clear() error
|
|
|
+}
|
|
|
+
|
|
|
+func Set(cache Cache, key string, value any) error {
|
|
|
+ valueReflectValue := reflect.ValueOf(value)
|
|
|
+
|
|
|
+ if !valueReflectValue.IsValid() {
|
|
|
+ return errors.New("缓存值无效")
|
|
|
+ }
|
|
|
+
|
|
|
+ stringValue, err := toString(valueReflectValue)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return cache.Set(key, stringValue)
|
|
|
+}
|
|
|
+
|
|
|
+func Get[T any](cache Cache, key string) (T, error) {
|
|
|
+ var zero T
|
|
|
+
|
|
|
+ stringValue, err := cache.Get(key)
|
|
|
+ if err != nil {
|
|
|
+ return zero, err
|
|
|
+ }
|
|
|
+
|
|
|
+ retValue := reflectutils.Zero[T]()
|
|
|
+ retValueReflectType := reflect.TypeOf(retValue)
|
|
|
+
|
|
|
+ if retValueReflectType.Kind() == reflect.Pointer {
|
|
|
+ err := fromString(stringValue, retValue)
|
|
|
+ if err != nil {
|
|
|
+ return zero, err
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ err := fromString(stringValue, &retValue)
|
|
|
+ if err != nil {
|
|
|
+ return zero, err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return retValue, nil
|
|
|
+}
|
|
|
+
|
|
|
+func GetMulti(cache Cache, keys []string) (map[string]string, error) {
|
|
|
+ return cache.GetMulti(keys)
|
|
|
+}
|
|
|
+
|
|
|
+func GetAll(cache Cache) (map[string]string, error) {
|
|
|
+ return cache.GetAll()
|
|
|
+}
|
|
|
+
|
|
|
+func Delete(cache Cache, key string) error {
|
|
|
+ return cache.Delete(key)
|
|
|
+}
|
|
|
+
|
|
|
+func Clear(cache Cache) error {
|
|
|
+ return cache.Clear()
|
|
|
+}
|
|
|
+
|
|
|
+func toString(valueReflectValue reflect.Value) (string, error) {
|
|
|
+ dataVal := reflect.Indirect(valueReflectValue)
|
|
|
+ dataKind := reflectutils.GroupValueKind(dataVal)
|
|
|
+
|
|
|
+ switch dataKind {
|
|
|
+ case reflect.String:
|
|
|
+ return dataVal.String(), nil
|
|
|
+ case reflect.Bool:
|
|
|
+ if dataVal.Bool() {
|
|
|
+ return "true", nil
|
|
|
+ } else {
|
|
|
+ return "false", nil
|
|
|
+ }
|
|
|
+ case reflect.Int64:
|
|
|
+ return strconv.FormatInt(dataVal.Int(), 10), nil
|
|
|
+ case reflect.Uint64:
|
|
|
+ return strconv.FormatUint(dataVal.Uint(), 10), nil
|
|
|
+ case reflect.Float64:
|
|
|
+ return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
|
|
|
+ case reflect.Slice, reflect.Array:
|
|
|
+ dataElementType := reflectutils.PointerTypeElem(dataVal.Type().Elem())
|
|
|
+
|
|
|
+ // []byte,直接转换为string
|
|
|
+ if dataElementType.Kind() == reflect.Uint8 {
|
|
|
+ if dataVal.Len() == 0 {
|
|
|
+ return "", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ uints := make([]uint8, dataVal.Len(), dataVal.Len())
|
|
|
+ for i := 0; i < dataVal.Len(); i++ {
|
|
|
+ uints[i] = dataVal.Index(i).Interface().(uint8)
|
|
|
+ }
|
|
|
+
|
|
|
+ return string(uints), nil
|
|
|
+ } else {
|
|
|
+ if dataVal.Len() == 0 {
|
|
|
+ return "[]", nil
|
|
|
+ }
|
|
|
+
|
|
|
+ stringBuilder := strings.Builder{}
|
|
|
+ stringBuilder.WriteString("[")
|
|
|
+
|
|
|
+ for i := 0; i < dataVal.Len(); i++ {
|
|
|
+ strValue, err := toString(dataVal.Index(i))
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+
|
|
|
+ if i > 0 {
|
|
|
+ stringBuilder.WriteString(",")
|
|
|
+ }
|
|
|
+
|
|
|
+ stringBuilder.WriteString(strValue)
|
|
|
+ }
|
|
|
+
|
|
|
+ stringBuilder.WriteString("]")
|
|
|
+
|
|
|
+ return stringBuilder.String(), nil
|
|
|
+ }
|
|
|
+ case reflect.Map, reflect.Struct:
|
|
|
+ if dataVal.Type().Name() == "time.Time" {
|
|
|
+ return dataVal.Interface().(time.Time).Format(time.RFC3339Nano), nil
|
|
|
+ } else {
|
|
|
+ jsonBytes, err := json.Marshal(dataVal.Interface())
|
|
|
+ if err != nil {
|
|
|
+ return "", errors.New(err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ return string(jsonBytes), nil
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return "", errors.New("不支持的缓存值类型: " + dataVal.Type().Elem().String())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func fromString(stringValue string, retValue any) error {
|
|
|
+ retValueReflectValue := reflect.ValueOf(retValue)
|
|
|
+
|
|
|
+ if retValueReflectValue.Kind() != reflect.Pointer {
|
|
|
+ return errors.New("返回值不是指针类型")
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal := reflect.Indirect(retValueReflectValue)
|
|
|
+ dataKind := reflectutils.GroupValueKind(dataVal)
|
|
|
+
|
|
|
+ switch dataKind {
|
|
|
+ case reflect.String:
|
|
|
+ dataVal.SetString(stringValue)
|
|
|
+ return nil
|
|
|
+ case reflect.Bool:
|
|
|
+ if strutils.IsStringEmpty(stringValue) {
|
|
|
+ dataVal.SetBool(false)
|
|
|
+ } else {
|
|
|
+ if stringValue == "false" {
|
|
|
+ dataVal.SetBool(false)
|
|
|
+ } else {
|
|
|
+ dataVal.SetBool(true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ case reflect.Int64:
|
|
|
+ intValue, err := strconv.ParseInt(stringValue, 10, 64)
|
|
|
+ if err != nil {
|
|
|
+ return errors.New(err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.SetInt(intValue)
|
|
|
+ return nil
|
|
|
+ case reflect.Uint64:
|
|
|
+ uintValue, err := strconv.ParseUint(stringValue, 10, 64)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.SetUint(uintValue)
|
|
|
+ return nil
|
|
|
+ case reflect.Float64:
|
|
|
+ floatValue, err := strconv.ParseFloat(stringValue, 64)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.SetFloat(floatValue)
|
|
|
+ return nil
|
|
|
+ case reflect.Slice, reflect.Array:
|
|
|
+ dataElementType := reflectutils.PointerTypeElem(dataVal.Type().Elem())
|
|
|
+
|
|
|
+ // []byte直接用string赋值
|
|
|
+ if dataElementType.Kind() == reflect.Uint8 {
|
|
|
+ dataSliceVal := reflect.MakeSlice(dataVal.Type(), 0, 0)
|
|
|
+
|
|
|
+ for _, b := range []byte(stringValue) {
|
|
|
+ if dataVal.Type().Elem().Kind() == reflect.Pointer {
|
|
|
+ dataSliceVal = reflect.Append(dataSliceVal, reflect.ValueOf(&b))
|
|
|
+ } else {
|
|
|
+ dataSliceVal = reflect.Append(dataSliceVal, reflect.ValueOf(b))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.Set(dataSliceVal)
|
|
|
+
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ if !strings.HasPrefix(stringValue, "[") || !strings.HasSuffix(stringValue, "]") {
|
|
|
+ return errors.New("缓存值不是切片或数组形式")
|
|
|
+ }
|
|
|
+
|
|
|
+ dataSliceVal := reflect.MakeSlice(dataVal.Type(), 0, 0)
|
|
|
+
|
|
|
+ stringValue = strings.TrimSuffix(strings.TrimPrefix(stringValue, "["), "]")
|
|
|
+ stringValueParts := strings.Split(stringValue, ",")
|
|
|
+
|
|
|
+ for _, strValuePart := range stringValueParts {
|
|
|
+ dataSliceElementType := dataVal.Type().Elem()
|
|
|
+ dataSliceElementVal := reflect.Indirect(reflect.New(dataSliceElementType))
|
|
|
+
|
|
|
+ if dataSliceElementVal.Kind() == reflect.Pointer {
|
|
|
+ dataSliceElementVal.Set(reflect.New(dataSliceElementVal.Type().Elem()))
|
|
|
+
|
|
|
+ err := fromString(strValuePart, dataSliceElementVal.Interface())
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ err := fromString(strValuePart, dataSliceElementVal.Addr().Interface())
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ dataSliceVal = reflect.Append(dataSliceVal, dataSliceElementVal)
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.Set(dataSliceVal)
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ case reflect.Map, reflect.Struct:
|
|
|
+ if dataVal.Type().Name() == "time.Time" {
|
|
|
+ parsedTime, err := time.ParseInLocation(time.RFC3339Nano, stringValue, time.Local)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ dataVal.Set(reflect.ValueOf(parsedTime))
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ err := json.Unmarshal([]byte(stringValue), dataVal.Addr().Interface())
|
|
|
+ if err != nil {
|
|
|
+ return errors.New(err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return errors.New("不支持的缓存值类型: " + dataVal.Type().Elem().String())
|
|
|
+ }
|
|
|
+}
|