f5/metamgr.go
aozhiwei 2674163215 1
2020-09-10 11:15:29 +08:00

317 lines
8.5 KiB
Go

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)
}
}
}
}