最近在解析一个网站的websocket时,发现使用的是protobuf,每个消息都使用一个统一的Wrapper封装,wrapper中包含有这条消息的pb名字以及对应的实际数据,这样就可以同时在同步通讯和通知中解析不同类型的消息了。
# 原格式
"Wrapper": {
"fields": {
"data": {
"id": 2,
"type": "bytes"
},
"name": {
"id": 1,
"type": "string"
}
}
}
# 转换为.proto
type Wrapper struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
![](https://img.haomeiwen.com/i8180869/36a477f9f28c88b0.png)
其中
.lq.RecordDealTile
为pb中的消息名称,那么只需要对每个消息根据名称实例化对应的消息就可以了。golang中语言级别是没有遍历包下所有类型的方法的,不过好在protobuf解决了这个问题,在生成的.pb.go中我们可以看到,每个类型都被注册到了proto中,我们需要使用的时候直接去获取就可以了。
![](https://img.haomeiwen.com/i8180869/d80044e07a9df1f7.png)
首先进行解码
func unWrap(b []byte) (s string, data []byte, err error) {
wrapper := lq.Wrapper{}
if err := wrapper.XXX_Unmarshal(b); err != nil {
fmt.Println("UnWrapper fail", err)
return "", nil, err
}
return wrapper.Name, wrapper.Data, nil
}
在解析数据时,直接使用proto.MessageType(name)
即可获得对应的消息类型。
fmt.Println(proto.MessageType(name))
> *lq.RecordDiscardTile
网友评论