package f5 import ( "os" "bufio" "strings" "reflect" "fmt" "strconv" "encoding/json" "q5" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/jsonpb" "google.golang.org/protobuf/reflect/protoreflect" ) type MetaClass struct { FileName string Idx int RawMeta interface{} WrapMeta interface{} PrimKey string SecKey string eleMeta reflect.Type } type MetaMgr struct { metaClasses *[]MetaClass rawList []interface{} wrapList []interface{} wrapIdHash []map[int64]interface{} wrapNameHash []map[string]interface{} } func (this *MetaMgr) Init() { } func (this *MetaMgr) UnInit() { } func (this *MetaMgr) RegisterMetaClasses(metaClasses *[]MetaClass) { for i := 0; i < len(*metaClasses); i++ { metaClass := &(*metaClasses)[i] msgType := reflect.TypeOf(metaClass.RawMeta).Elem() msg := reflect.New(msgType) metaClass.eleMeta = reflect.TypeOf(msg.Elem().FieldByName("Values").Interface()).Elem().Elem() if metaClass.eleMeta == nil { panic(fmt.Sprintf( "registerMetaClasses error not found Values field %s", metaClass.FileName)) } } this.metaClasses = metaClasses } func (this *MetaMgr) Load() { this.rawList = make([]interface{}, len(*this.metaClasses)) this.wrapList = make([]interface{}, len(*this.metaClasses)) this.wrapIdHash = make([]map[int64]interface{}, len(*this.metaClasses)) this.wrapNameHash = make([]map[string]interface{}, len(*this.metaClasses)) this.loadRawMetaTable() this.bindPrimKey() this.firstInitMetaList() this.secondInitMetaList() } func (this *MetaMgr) loadRawMetaTable() { for _, metaClass := range *this.metaClasses { rawMeta, _ := this.loadJson(&metaClass) values := rawMeta.Elem().FieldByName("Values") wrapMetaType := reflect.TypeOf(metaClass.WrapMeta) wrapMetaList := reflect.MakeSlice(reflect.SliceOf(wrapMetaType), 0, values.Len()) for i := 0; i < values.Len(); i++ { val := values.Index(i) wrapMeta := reflect.New(reflect.TypeOf(wrapMetaList.Interface()).Elem().Elem()) clsName := reflect.TypeOf(val.Elem().Interface()).Name() clsField := wrapMeta.Elem().FieldByName(clsName) clsField.Set(val) wrapMetaList = reflect.Append(wrapMetaList, wrapMeta) } this.rawList[metaClass.Idx] = rawMeta this.wrapList[metaClass.Idx] = wrapMetaList.Interface() this.wrapIdHash[metaClass.Idx] = map[int64]interface{}{} this.wrapNameHash[metaClass.Idx] = map[string]interface{}{} } } func (this *MetaMgr) bindPrimKey() { bindFunc := func (metaClass *MetaClass, wrapMeta reflect.Value) { primVal := wrapMeta.Elem().FieldByName(metaClass.PrimKey) secVal := wrapMeta.Elem().FieldByName(metaClass.SecKey) nameHash := this.wrapNameHash[metaClass.Idx] idHash := this.wrapIdHash[metaClass.Idx] if fieldVal, ok := primVal.Interface().(*string); ok { if _, ok := nameHash[*fieldVal]; ok { panic(fmt.Sprintf( "bindPrimKey duplicated key error %s %s", metaClass.FileName, *fieldVal)) } nameHash[*fieldVal] = wrapMeta } else if fieldVal, ok := primVal.Interface().(*int32); ok { if metaClass.SecKey == "" { if _, ok := idHash[int64(*fieldVal)]; ok { panic(fmt.Sprintf( "bindPrimKey duplicated key error %s %s", metaClass.FileName, *fieldVal)) } idHash[int64(*fieldVal)] = wrapMeta.Interface() } else { if subFieldVal, ok := secVal.Interface().(*int32); ok { if _, ok := idHash[q5.MkInt64(*fieldVal, *subFieldVal)]; ok { panic(fmt.Sprintf( "bindPrimKey duplicated key error %s %s", metaClass.FileName, q5.MkInt64(*fieldVal, *subFieldVal))) } idHash[q5.MkInt64(*fieldVal, *subFieldVal)] = wrapMeta.Interface() } else { panic(fmt.Sprintf("bindPrimKey subField error %s", metaClass.FileName)) } } } else { panic(fmt.Sprintf("bindPrimKey primKey error %s", metaClass.FileName)) } } for _, metaClass := range *this.metaClasses { wrapMetaList := reflect.ValueOf(this.wrapList[metaClass.Idx]) for i := 0; i < wrapMetaList.Len(); i++ { wrapMeta := wrapMetaList.Index(i) if metaClass.PrimKey == "" { this.wrapIdHash[metaClass.Idx][int64(i + 1)] = wrapMeta.Interface() } else { bindFunc(&metaClass, wrapMeta) } } } } func (this *MetaMgr) loadJson(metaClass *MetaClass) (reflect.Value, error) { if f, err := os.Open(metaClass.FileName); err == nil { data, _ := bufio.NewReader(f).ReadString(0) switch q5.JsonStrType(data) { case q5.JSON_ARRAY: break case q5.JSON_OBJECT: data = "[" + data + "]" default: panic(fmt.Sprintf("error json format %s", metaClass.FileName)) } data = this.adjustJsonForamt(metaClass, data) data = "{\"values\":" + data + "}" msgType := reflect.TypeOf(metaClass.RawMeta).Elem() msg := reflect.New(msgType) msgPb := msg.Interface().(proto.Message) u := jsonpb.Unmarshaler{AllowUnknownFields: true} err := u.Unmarshal(strings.NewReader(data), msgPb) if err != nil { panic(fmt.Sprintf( "parse json error %s %s %s", err, metaClass.FileName, msgType.Name())) } return msg, err } else { panic(fmt.Sprintf("open metafile error %s %s", metaClass.FileName, err)) } } func (this *MetaMgr) GetMetaById(idx int, id int32) interface{} { return this.GetMetaById64(idx, int64(id)) } func (this *MetaMgr) GetMetaById64(idx int, id int64) interface{} { if idx >=0 && idx < len(this.wrapIdHash) { idHash := this.wrapIdHash[idx] if v, ok := idHash[id]; ok { return reflect.ValueOf(v).Interface() } else { return nil } } return nil } func (this *MetaMgr) GetMetaByName(idx int, name string) interface{} { if idx >=0 && idx < len(this.wrapNameHash) { nameHash := this.wrapNameHash[idx] if v, ok := nameHash[name]; ok { return v } else { return nil } } return nil } func (this *MetaMgr) GetMetaList(idx int) interface{} { if idx >=0 && idx < len(this.wrapList) { return this.wrapList[idx] } return nil } func (this *MetaMgr) adjustJsonForamt(metaClass *MetaClass, rawData string) string { adjustFieldFunc := func(msg map[string]interface{}, key string, val interface{}, field protoreflect.FieldDescriptor) { switch field.Kind() { case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind, protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind, protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind: if q5.IsNumberType(val) { } else if reflect.TypeOf(val).Kind() == reflect.String { strVal := val.(string) if strVal == "" { msg[key] = 0 } else { intVal, err := strconv.ParseInt(strVal, 10, 64) if err == nil { msg[key] = intVal } else { floatVal, err := strconv.ParseFloat(strVal, 64) if err == nil { msg[key] = floatVal } else { panic(fmt.Sprintf( "adjustJsonFormat error %s %s %s", metaClass.FileName, key, val)) } } } } case protoreflect.BoolKind, protoreflect.EnumKind, protoreflect.BytesKind, //protoreflect.MessageKind, protoreflect.GroupKind: panic(fmt.Sprintf( "adjustJsonFormat error %s %s %s", metaClass.FileName, key, val)) case protoreflect.MessageKind: break } } var rawJson []map[string]interface{} err := json.Unmarshal([]byte(rawData), &rawJson) if err != nil { panic(fmt.Sprintf("adjustJsonFormat unmarshal error %s %s", metaClass.FileName, err)) } msgType := proto.MessageReflect(reflect.New(metaClass.eleMeta).Interface().(proto.Message)) for i := 0; i < len(rawJson); i++ { msg := rawJson[i] for key, val := range msg { field := msgType.Descriptor().Fields().ByName(protoreflect.Name(key)) if field != nil { adjustFieldFunc(msg, key, val, field) } } } newData, err := json.Marshal(rawJson) //fmt.Println("rawData ", string(rawData)) //fmt.Println("newData ", string(newData)) if err != nil { panic(fmt.Sprintf("adjustJsonFormat marshal error %s %s", metaClass.FileName, err)) } return string(newData) } func (this *MetaMgr) firstInitMetaList() { for i := 0; i < len(this.wrapList); i++ { metaList := reflect.ValueOf(this.wrapList[i]) for ii := 0; ii < metaList.Len(); ii++ { meta := metaList.Index(ii) initFunc := meta.MethodByName("Init") if initFunc.IsValid() { initFunc.Call(nil) } } } } func (this *MetaMgr) secondInitMetaList() { for i := 0; i < len(this.wrapList); i++ { metaList := reflect.ValueOf(this.wrapList[i]) for i := 0; i < metaList.Len(); i++ { meta := metaList.Index(i) init2Func := meta.MethodByName("Init2") if init2Func.IsValid() { init2Func.Call(nil) } } } }