有时,需要动态的根据proto文件来构建一个proto对象。此时,就该反射库上场了。
代码语言:javascript复制package jsonpb
import (
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoparse"
"github.com/jhump/protoreflect/dynamic"
"github.com/rfyiamcool/grpcall"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"sync"
)
var globalProtoMap map[string]*desc.FileDescriptor
var IsCached = true
var lk sync.RWMutex
func init() {
globalProtoMap = make(map[string]*desc.FileDescriptor)
}
func getProto(path string) *desc.FileDescriptor {
lk.Lock()
defer lk.Unlock()
if IsCached {
fd, ok := globalProtoMap[path]
if ok {
logging.Debugf("getProto path:%v cached", path)
return fd
}
}
p := protoparse.Parser{
}
fds, err := p.ParseFiles(path)
if err != nil {
logging.Errorf("getProto ParseFiles error:%v", err)
return nil
}
//logging.Debugf("JsonToPb fd %v, err %v", fds[0], err)
fd := fds[0]
if IsCached {
globalProtoMap[path] = fd
}
return fd
}
// JsonToPb 传入proto文件的path, proto中对应的message.name,js的原始数据
// 返回生成的proto.Marshal的[]byte
// example:
// path := "$PROTOPATH/helloworld.proto"
// messageName "helloworld.HelloRequest"
// JsonToPb(path,"helloworld.HelloRequest", []byte(`{"name":"yzh"}`))
func JsonToPb(protoPath, messageName string, jsonStr []byte) ([]byte, error) {
logging.Debugf("JsonToPb protoPath %v", protoPath)
fd := getProto(protoPath)
msg := fd.FindMessage(messageName)
dymsg := dynamic.NewMessage(msg)
err := dymsg.UnmarshalJSON(jsonStr)
if err != nil {
logging.Errorf("JsonToPb UnmarshalJSON error:%v", err)
return nil, nil
}
logging.Debugf("JsonToPb UnmarshalJSON dymsg %v", dymsg)
any, err := ptypes.MarshalAny(dymsg)
if err != nil {
logging.Errorf("JsonToPb MarshalAny error:%v", err)
return nil, nil
}
logging.Debugf("JsonToPb marshal any %v", any.Value)
return any.Value, nil
}
// PbToJson 传入proto的byte数据,返回它对应的json数据
// example:
// path := "$PROTOPATH/helloworld.proto"
// messageName "helloworld.HelloRequest"
// jsonByte, err := PbToJson(path, messageName, pbByte)
func PbToJson(protoPath, messageName string, protoData []byte) ([]byte, error) {
logging.Debugf("PbToJson protoPath %v", protoPath)
fd := getProto(protoPath)
msg := fd.FindMessage(messageName)
dymsg := dynamic.NewMessage(msg)
err := proto.Unmarshal(protoData, dymsg)
logging.Debugf("PbToJson Unmarshal err:%v", err)
jsonByte, err := dymsg.MarshalJSON()
return jsonByte, err
}