164 lines
3.9 KiB
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
|
|
}
|