在基于Tendermint增加一个已有rpc接口参数的时候,是考虑增加接口还是扩张接口,这两者都比较麻烦
增加接口的话扩展性不强
扩展接口的话也比较麻烦,一整套接口都得改,而且后续扩展性不强
想着在数据的前面加一个byte代表类型,接收方去获取第一个byte判断类型后续为数据,但是这样有点赤裸裸的workaround的感觉了,看到已有的go-wire有类似效果,就是这个想法上的包装,所以看看怎么使用的
go-wire是什么
查了下没查到,看起来是Tendermint自己做的?
它的作用是传输数据的时候按照定义的格式encode为二进制传输,接收端接收到数据后按照定义的格式decode二进制位结构化数据。
初始化
使用之前需要先注册,以Tendermint的mempool为例
var _ = wire.RegisterInterface(
struct{ MempoolMessage }{},
wire.ConcreteType{&TxMessage{}, msgTypeTx},
wire.ConcreteType{&TxMessage{}, msgTypeTx},
)
为了方便演示,我将第3行复制了一遍
需要调用wire的RegisterInterface
func RegisterInterface(o interface{}, ctypes ...ConcreteType) *TypeInfo {
it := GetTypeFromStructDeclaration(o)
if it.Kind() != reflect.Interface {
cmn.PanicSanity("RegisterInterface expects an interface")
}
toType := make(map[byte]reflect.Type, 0)
toByte := make(map[reflect.Type]byte, 0)
for _, ctype := range ctypes {
crt := reflect.TypeOf(ctype.O)
typeByte := ctype.Byte
if typeByte == 0x00 {
cmn.PanicSanity(cmn.Fmt("Byte of 0x00 is reserved for nil (%v)", ctype))
}
if toType[typeByte] != nil {
cmn.PanicSanity(cmn.Fmt("Duplicate Byte for type %v and %v", ctype, toType[typeByte]))
}
toType[typeByte] = crt
toByte[crt] = typeByte
}
typeInfo := &TypeInfo{
Type: it,
IsRegisteredInterface: true,
ByteToType: toType,
TypeToByte: toByte,
}
typeInfos[it] = typeInfo
return typeInfo
}
1 获取o的struct type,其实就是获取到了类型MempoolMessage
2 for循环ctypes参数,也就是剩下的其余的参数
拿到ctype的类型crt和值typeByte(该值不能为0,0默认为nil),然后分别加入到map toType和toByte,
组织为TypeInfo返回,同时加入到最后加入到map typesInfos中
所以初始化的目的就是把定义的type和value加入到map typesInfos中, type为key。typeInfos中的元素就是解析好的value,有两个map保存value结构type和value
写入数据
写入数据的时候调用接口BinaryBytes。以上述为例子,写入的参数为
struct{ MempoolMessage }{msg},(其中msg为&TxMessage{Tx: tx})就是下面的参数o
func BinaryBytes(o interface{}) []byte {
w, n, err := new(bytes.Buffer), new(int), new(error)
WriteBinary(o, w, n, err)
if *err != nil {
cmn.PanicSanity(*err)
}
return w.Bytes()
}
接着看WriteBinary
func WriteBinary(o interface{}, w io.Writer, n *int, err *error) {
rv := reflect.ValueOf(o)
rt := reflect.TypeOf(o)
writeReflectBinary(rv, rt, Options{}, w, n, err)
}
这里要获取参数的value和type,分别为msg何MempoolMessage
接下来的writeReflectBinary就是把结构化的数据转成byte数组最终传递出去了
unc writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Writer, n *int, err *error) {
// Get typeInfo
typeInfo := GetTypeInfo(rt)
if rt.Kind() == reflect.Interface {
if rv.IsNil() {
WriteByte(0x00, w, n, err)
return
}
crv := rv.Elem() // concrete reflection value
crt := crv.