-
Notifications
You must be signed in to change notification settings - Fork 4
/
gate_codec.go
121 lines (112 loc) · 3.88 KB
/
gate_codec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package internal
import (
"encoding/binary"
. "github.com/fish-tennis/gnet"
"google.golang.org/protobuf/proto"
"reflect"
"github.com/fish-tennis/gserver/logger"
)
// gate和其他服务器之间的编解码
type GateCodec struct {
RingBufferCodec
// 在proto序列化后的数据,再做一层编码
// encoder after proto.Message serialize
ProtoPacketBytesEncoder func(protoPacketBytes [][]byte) [][]byte
// 在proto反序列化之前,先做一层解码
// decoder before proto.Message deserialize
ProtoPacketBytesDecoder func(packetData []byte) []byte
// 消息号和proto.Message type的映射表
MessageCreatorMap map[PacketCommand]reflect.Type
}
func NewGateCodec(protoMessageTypeMap map[PacketCommand]reflect.Type) *GateCodec {
codec := &GateCodec{
RingBufferCodec: RingBufferCodec{},
MessageCreatorMap: protoMessageTypeMap,
}
if codec.MessageCreatorMap == nil {
codec.MessageCreatorMap = make(map[PacketCommand]reflect.Type)
}
codec.DataEncoder = codec.EncodePacket
codec.DataDecoder = codec.DecodePacket
return codec
}
// 注册消息和proto.Message的映射
//
// protoMessage can be nil
func (this *GateCodec) Register(command PacketCommand, protoMessage proto.Message) {
if protoMessage == nil {
this.MessageCreatorMap[command] = nil
return
}
this.MessageCreatorMap[command] = reflect.TypeOf(protoMessage).Elem()
}
func (this *GateCodec) EncodePacket(connection Connection, packet Packet) [][]byte {
gatePacket,_ := packet.(*GatePacket)
protoMessage := packet.Message()
// 先写入消息号
// write PacketCommand
commandBytes := make([]byte, 10)
binary.LittleEndian.PutUint16(commandBytes, uint16(packet.Command()))
// write PlayerId
binary.LittleEndian.PutUint64(commandBytes[2:], uint64(gatePacket.PlayerId()))
var messageBytes []byte
if protoMessage != nil {
var err error
messageBytes, err = proto.Marshal(protoMessage)
if err != nil {
logger.Error("proto encode err:%v cmd:%v", err, packet.Command())
return nil
}
} else {
// 支持提前序列化好的数据
// support direct encoded data from application layer
messageBytes = packet.GetStreamData()
}
// 这里可以继续对messageBytes进行编码,如异或,加密,压缩等
// you can continue to encode messageBytes here, such as XOR, encryption, compression, etc
if this.ProtoPacketBytesEncoder != nil {
return this.ProtoPacketBytesEncoder([][]byte{commandBytes, messageBytes})
}
return [][]byte{commandBytes, messageBytes}
}
func (this *GateCodec) DecodePacket(connection Connection, packetHeader PacketHeader, packetData []byte) Packet {
decodedPacketData := packetData
// Q:这里可以对packetData进行解码,如异或,解密,解压等
// you can decode packetData here, such as XOR, encryption, compression, etc
if this.ProtoPacketBytesDecoder != nil {
decodedPacketData = this.ProtoPacketBytesDecoder(packetData)
}
if len(decodedPacketData) < 10 {
return nil
}
command := binary.LittleEndian.Uint16(decodedPacketData[:2])
playerId := int64(binary.LittleEndian.Uint64(decodedPacketData[2:10]))
if protoMessageType, ok := this.MessageCreatorMap[PacketCommand(command)]; ok {
if protoMessageType != nil {
newProtoMessage := reflect.New(protoMessageType).Interface().(proto.Message)
err := proto.Unmarshal(decodedPacketData[10:], newProtoMessage)
if err != nil {
logger.Error("proto decode err:%v cmd:%v", err, command)
return nil
}
return &GatePacket{
command: PacketCommand(command),
playerId: playerId,
message: newProtoMessage,
}
} else {
// 支持只注册了消息号,没注册proto结构体的用法
// support Register(command, nil), return the direct stream data to application layer
return &GatePacket{
command: PacketCommand(command),
playerId: playerId,
data: decodedPacketData[10:],
}
}
}
return &GatePacket{
command: PacketCommand(command),
playerId: playerId,
data: decodedPacketData[10:],
}
}