goserver_sync/core/netlib/encoding.go

164 lines
3.9 KiB
Go

// encoding
package netlib
import (
"bytes"
"encoding/binary"
"fmt"
"google.golang.org/protobuf/proto"
)
const (
EncodingTypeNil = iota
EncodingTypeGPB
EncodingTypeBinary
EncodingTypeGob
EncodingTypeMax
)
var (
encodingArray [EncodingTypeMax]EncDecoder
typeTesters [EncodingTypeMax]TypeTester
)
type EncDecoder interface {
Unmarshal(buf []byte, pack interface{}) error
Marshal(pack interface{}) ([]byte, error)
}
type UnparsePacketTypeErr struct {
EncodeType int16
PacketId int16
Err error
}
type TypeTester func(pack interface{}) int
func (this *UnparsePacketTypeErr) Error() string {
return fmt.Sprintf("cannot parse proto type:%v packetid:%v err:%v", this.EncodeType, this.PacketId, this.Err)
}
func NewUnparsePacketTypeErr(et, packid int16, err error) *UnparsePacketTypeErr {
return &UnparsePacketTypeErr{EncodeType: et, PacketId: packid, Err: err}
}
func UnmarshalPacket(data []byte) (int, interface{}, error) {
var ph PacketHeader
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &ph)
if err != nil {
return int(ph.PacketId), nil, err
}
if ph.EncodeType >= EncodingTypeMax {
return int(ph.PacketId), nil, NewUnparsePacketTypeErr(ph.EncodeType, ph.PacketId, fmt.Errorf("EncodeType:%d unregiste", ph.EncodeType))
}
pck := CreatePacket(int(ph.PacketId))
if pck == nil {
return int(ph.PacketId), nil, NewUnparsePacketTypeErr(ph.EncodeType, ph.PacketId, fmt.Errorf("packetId:%d unregiste", ph.PacketId))
} else {
err = encodingArray[ph.EncodeType].Unmarshal(data[LenOfPacketHeader:], pck)
return int(ph.PacketId), pck, err
}
return 0, nil, nil
}
func MarshalPacket(packetid int, pack interface{}) ([]byte, error) {
et := typetest(pack)
if et < EncodingTypeNil || et > EncodingTypeMax {
return nil, fmt.Errorf("MarshalPacket unkown data type:%v", et)
}
if encodingArray[et] == nil {
return nil, fmt.Errorf("MarshalPacket unkown data type:%v", et)
}
data, err := encodingArray[et].Marshal(pack)
if err != nil {
return nil, fmt.Errorf("%v %v", pack, err.Error())
}
ph := PacketHeader{
EncodeType: int16(et),
PacketId: int16(packetid),
}
w := bytes.NewBuffer(nil)
binary.Write(w, binary.LittleEndian, &ph)
binary.Write(w, binary.LittleEndian, data)
return w.Bytes(), nil
}
func MarshalPacketNoPackId(pack interface{}) (data []byte, err error) {
et := typetest(pack)
if et < EncodingTypeNil || et > EncodingTypeMax {
return nil, fmt.Errorf("MarshalPacket unkown data type:%v", et)
}
if encodingArray[et] == nil {
return nil, fmt.Errorf("MarshalPacket unkown data type:%v", et)
}
data, err = encodingArray[et].Marshal(pack)
if err != nil {
return nil, fmt.Errorf("%v %v", pack, err.Error())
}
ph := PacketHeader{
EncodeType: int16(et),
PacketId: int16(0),
}
w := bytes.NewBuffer(nil)
binary.Write(w, binary.LittleEndian, &ph)
binary.Write(w, binary.LittleEndian, data)
return w.Bytes(), nil
}
func UnmarshalPacketNoPackId(data []byte, pck interface{}) error {
var ph PacketHeader
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &ph)
if err != nil {
return err
}
if ph.EncodeType >= EncodingTypeMax {
return NewUnparsePacketTypeErr(ph.EncodeType, ph.PacketId, fmt.Errorf("EncodeType:%d unregiste", ph.EncodeType))
}
err = encodingArray[ph.EncodeType].Unmarshal(data[LenOfPacketHeader:], pck)
if err != nil {
return NewUnparsePacketTypeErr(ph.EncodeType, ph.PacketId, err)
}
return err
}
func SkipHeaderGetRaw(data []byte) []byte {
if len(data) < LenOfPacketHeader {
return nil
}
return data[LenOfPacketHeader:]
}
func typetest(pack interface{}) int {
switch pack.(type) {
case proto.Message:
return EncodingTypeGPB
case []byte:
return EncodingTypeBinary
default:
return EncodingTypeGob
}
return -1
}
func RegisteEncoding(edtype int, ed EncDecoder, tt TypeTester) {
if encodingArray[edtype] != nil {
panic(fmt.Sprintf("repeated registe EncDecoder %d", edtype))
}
encodingArray[edtype] = ed
typeTesters[edtype] = tt
}