-
Notifications
You must be signed in to change notification settings - Fork 3
/
init.go
103 lines (85 loc) · 2.73 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package dynamic
import (
"errors"
"github.com/golang/protobuf/proto"
dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoparse"
"github.com/jhump/protoreflect/dynamic"
)
var (
RepetitivePackageNameErr = errors.New("repetitive package name")
)
type DynamicParser struct {
packageName string
parser *protoparse.Parser
fileDesc []*desc.FileDescriptor
enumDescMap map[string]*desc.EnumDescriptor
messageDescMap map[string]*desc.MessageDescriptor
}
func NewDynamicParser() *DynamicParser {
return &DynamicParser{
parser: &protoparse.Parser{},
fileDesc: nil,
enumDescMap: make(map[string]*desc.EnumDescriptor),
messageDescMap: make(map[string]*desc.MessageDescriptor),
}
}
func (dynamicParser *DynamicParser) SetImportPath(importPaths ...string) {
dynamicParser.parser.ImportPaths = importPaths
}
func (dynamicParser *DynamicParser) ParseFiles(filenames ...string) error {
fileDesc, err := dynamicParser.parser.ParseFiles(filenames...)
if err != nil {
return err
}
dynamicParser.fileDesc = fileDesc
// get all desc
for _, _desc := range fileDesc {
if dynamicParser.packageName != "" && dynamicParser.packageName != _desc.GetPackage() {
return RepetitivePackageNameErr
}
dynamicParser.packageName = _desc.GetPackage()
for _, v := range _desc.GetMessageTypes() {
dynamicParser.messageDescMap[v.GetName()] = v
}
for _, v := range _desc.GetEnumTypes() {
dynamicParser.enumDescMap[v.GetName()] = v
}
}
return nil
}
func (dynamicParser *DynamicParser) ParseToMap(messageName string, protocolID int32, data []byte) (string, []interface{}, error) {
msgDesc, isExist := dynamicParser.messageDescMap[messageName]
if !isExist {
return "", nil, errors.New("message `" + messageName + "` is absent")
}
msg := dynamic.NewMessage(msgDesc)
if err := proto.Unmarshal(data, msg); err != nil {
return "", nil, err
}
return msgDesc.FindFieldByNumber(protocolID).GetMessageType().GetName(), dynamicParser.toMap(msgDesc, msg), nil
}
func (dynamicParser *DynamicParser) toMap(msgDesc *desc.MessageDescriptor, msg *dynamic.Message) []interface{} {
var ret []interface{}
if msg == (*dynamic.Message)(nil) {
return ret
}
for _, fieldDesc := range msgDesc.GetFields() {
fieldValue := msg.GetField(fieldDesc)
switch fieldDesc.GetType() {
case dpb.FieldDescriptorProto_TYPE_MESSAGE:
subMsgDesc, isExist := dynamicParser.messageDescMap[fieldDesc.GetMessageType().GetName()]
if isExist {
if t, flag := fieldValue.(*dynamic.Message); !flag {
continue
} else {
ret = append(ret, dynamicParser.toMap(subMsgDesc, t)...)
}
}
default:
ret = append(ret, fieldValue)
}
}
return ret
}