init commit

This commit is contained in:
flswld
2022-11-20 15:38:00 +08:00
parent eda2b643b9
commit 3efed3defe
5834 changed files with 636508 additions and 0 deletions

View File

@@ -0,0 +1,387 @@
package net
import (
"bytes"
"encoding/binary"
"flswld.com/common/config"
"flswld.com/common/utils/random"
"flswld.com/logger"
"gate-hk4e/kcp"
"io/ioutil"
"strconv"
"sync"
"time"
)
type KcpXorKey struct {
encKey []byte
decKey []byte
}
type KcpConnectManager struct {
openState bool
connMap map[uint64]*kcp.UDPSession
connMapLock sync.RWMutex
protoMsgInput chan *ProtoMsg
protoMsgOutput chan *ProtoMsg
kcpEventInput chan *KcpEvent
kcpEventOutput chan *KcpEvent
// 发送协程分发
kcpRawSendChanMap map[uint64]chan *ProtoMsg
kcpRawSendChanMapLock sync.RWMutex
// 收包发包监听标志
kcpRecvListenMap map[uint64]bool
kcpRecvListenMapLock sync.RWMutex
kcpSendListenMap map[uint64]bool
kcpSendListenMapLock sync.RWMutex
// key
dispatchKey []byte
secretKey []byte
kcpKeyMap map[uint64]*KcpXorKey
kcpKeyMapLock sync.RWMutex
// conv短时间内唯一生成
convGenMap map[uint64]int64
convGenMapLock sync.RWMutex
}
func NewKcpConnectManager(protoMsgInput chan *ProtoMsg, protoMsgOutput chan *ProtoMsg,
kcpEventInput chan *KcpEvent, kcpEventOutput chan *KcpEvent) (r *KcpConnectManager) {
r = new(KcpConnectManager)
r.openState = true
r.connMap = make(map[uint64]*kcp.UDPSession)
r.protoMsgInput = protoMsgInput
r.protoMsgOutput = protoMsgOutput
r.kcpEventInput = kcpEventInput
r.kcpEventOutput = kcpEventOutput
r.kcpRawSendChanMap = make(map[uint64]chan *ProtoMsg)
r.kcpRecvListenMap = make(map[uint64]bool)
r.kcpSendListenMap = make(map[uint64]bool)
r.kcpKeyMap = make(map[uint64]*KcpXorKey)
r.convGenMap = make(map[uint64]int64)
return r
}
func (k *KcpConnectManager) Start() {
go func() {
// key
var err error = nil
k.dispatchKey, err = ioutil.ReadFile("static/dispatchKey.bin")
if err != nil {
logger.LOG.Error("open dispatchKey.bin error")
return
}
k.secretKey, err = ioutil.ReadFile("static/secretKey.bin")
if err != nil {
logger.LOG.Error("open secretKey.bin error")
return
}
// kcp
port := strconv.FormatInt(int64(config.CONF.Hk4e.KcpPort), 10)
listener, err := kcp.ListenWithOptions("0.0.0.0:"+port, nil, 0, 0)
if err != nil {
logger.LOG.Error("listen kcp err: %v", err)
return
} else {
go k.enetHandle(listener)
go k.chanSendHandle()
go k.eventHandle()
for {
conn, err := listener.AcceptKCP()
if err != nil {
logger.LOG.Error("accept kcp err: %v", err)
return
}
if k.openState == false {
_ = conn.Close()
continue
}
conn.SetACKNoDelay(true)
conn.SetWriteDelay(false)
convId := conn.GetConv()
logger.LOG.Debug("client connect, convId: %v", convId)
// 连接建立成功通知
k.kcpEventOutput <- &KcpEvent{
ConvId: convId,
EventId: KcpConnEstNotify,
EventMessage: conn.RemoteAddr().String(),
}
k.connMapLock.Lock()
k.connMap[convId] = conn
k.connMapLock.Unlock()
k.kcpKeyMapLock.Lock()
k.kcpKeyMap[convId] = &KcpXorKey{
encKey: k.dispatchKey,
decKey: k.dispatchKey,
}
k.kcpKeyMapLock.Unlock()
go k.recvHandle(convId)
kcpRawSendChan := make(chan *ProtoMsg, 10000)
k.kcpRawSendChanMapLock.Lock()
k.kcpRawSendChanMap[convId] = kcpRawSendChan
k.kcpRawSendChanMapLock.Unlock()
go k.sendHandle(convId, kcpRawSendChan)
go k.rttMonitor(convId)
}
}
}()
go k.clearDeadConv()
}
func (k *KcpConnectManager) clearDeadConv() {
ticker := time.NewTicker(time.Minute)
for {
k.convGenMapLock.Lock()
now := time.Now().UnixNano()
oldConvList := make([]uint64, 0)
for conv, timestamp := range k.convGenMap {
if now-timestamp > int64(time.Hour) {
oldConvList = append(oldConvList, conv)
}
}
delConvList := make([]uint64, 0)
k.connMapLock.RLock()
for _, conv := range oldConvList {
_, exist := k.connMap[conv]
if !exist {
delConvList = append(delConvList, conv)
delete(k.convGenMap, conv)
}
}
k.connMapLock.RUnlock()
k.convGenMapLock.Unlock()
logger.LOG.Info("clean dead conv list: %v", delConvList)
<-ticker.C
}
}
func (k *KcpConnectManager) enetHandle(listener *kcp.Listener) {
for {
enetNotify := <-listener.EnetNotify
logger.LOG.Info("[Enet Notify], addr: %v, conv: %v, conn: %v, enet: %v", enetNotify.Addr, enetNotify.ConvId, enetNotify.ConnType, enetNotify.EnetType)
switch enetNotify.ConnType {
case kcp.ConnEnetSyn:
if enetNotify.EnetType == kcp.EnetClientConnectKey {
var conv uint64
k.convGenMapLock.Lock()
for {
convData := random.GetRandomByte(8)
convDataBuffer := bytes.NewBuffer(convData)
_ = binary.Read(convDataBuffer, binary.LittleEndian, &conv)
_, exist := k.convGenMap[conv]
if exist {
continue
} else {
k.convGenMap[conv] = time.Now().UnixNano()
break
}
}
k.convGenMapLock.Unlock()
listener.SendEnetNotifyToClient(&kcp.Enet{
Addr: enetNotify.Addr,
ConvId: conv,
ConnType: kcp.ConnEnetEst,
EnetType: enetNotify.EnetType,
})
}
case kcp.ConnEnetEst:
case kcp.ConnEnetFin:
k.closeKcpConn(enetNotify.ConvId, enetNotify.EnetType)
case kcp.ConnEnetAddrChange:
// 连接地址改变通知
k.kcpEventOutput <- &KcpEvent{
ConvId: enetNotify.ConvId,
EventId: KcpConnAddrChangeNotify,
EventMessage: enetNotify.Addr,
}
default:
}
}
}
func (k *KcpConnectManager) chanSendHandle() {
// 分发到每个连接具体的发送协程
for {
protoMsg := <-k.protoMsgInput
k.kcpRawSendChanMapLock.RLock()
kcpRawSendChan := k.kcpRawSendChanMap[protoMsg.ConvId]
k.kcpRawSendChanMapLock.RUnlock()
if kcpRawSendChan != nil {
select {
case kcpRawSendChan <- protoMsg:
default:
logger.LOG.Error("kcpRawSendChan is full, convId: %v", protoMsg.ConvId)
}
} else {
logger.LOG.Error("kcpRawSendChan is nil, convId: %v", protoMsg.ConvId)
}
}
}
func (k *KcpConnectManager) recvHandle(convId uint64) {
// 接收
k.connMapLock.RLock()
conn := k.connMap[convId]
k.connMapLock.RUnlock()
pktFreqLimitCounter := 0
pktFreqLimitTimer := time.Now().UnixNano()
protoEnDecode := NewProtoEnDecode()
recvBuf := make([]byte, conn.GetMaxPayloadLen())
for {
_ = conn.SetReadDeadline(time.Now().Add(time.Second * 30))
recvLen, err := conn.Read(recvBuf)
if err != nil {
logger.LOG.Error("exit recv loop, conn read err: %v, convId: %v", err, convId)
k.closeKcpConn(convId, kcp.EnetServerKick)
break
}
pktFreqLimitCounter++
now := time.Now().UnixNano()
if now-pktFreqLimitTimer > int64(time.Second) {
if pktFreqLimitCounter > 1000 {
logger.LOG.Error("exit recv loop, client packet send freq too high, convId: %v, pps: %v", convId, pktFreqLimitCounter)
k.closeKcpConn(convId, kcp.EnetPacketFreqTooHigh)
break
} else {
pktFreqLimitCounter = 0
}
pktFreqLimitTimer = now
}
recvData := recvBuf[:recvLen]
k.kcpRecvListenMapLock.RLock()
flag := k.kcpRecvListenMap[convId]
k.kcpRecvListenMapLock.RUnlock()
if flag {
// 收包通知
//recvMsg := make([]byte, len(recvData))
//copy(recvMsg, recvData)
k.kcpEventOutput <- &KcpEvent{
ConvId: convId,
EventId: KcpPacketRecvNotify,
EventMessage: recvData,
}
}
kcpMsgList := make([]*KcpMsg, 0)
k.decodeBinToPayload(recvData, convId, &kcpMsgList)
for _, v := range kcpMsgList {
protoMsgList := protoEnDecode.protoDecode(v)
for _, vv := range protoMsgList {
k.protoMsgOutput <- vv
}
}
}
}
func (k *KcpConnectManager) sendHandle(convId uint64, kcpRawSendChan chan *ProtoMsg) {
// 发送
k.connMapLock.RLock()
conn := k.connMap[convId]
k.connMapLock.RUnlock()
protoEnDecode := NewProtoEnDecode()
for {
protoMsg, ok := <-kcpRawSendChan
if !ok {
logger.LOG.Error("exit send loop, send chan close, convId: %v", convId)
k.closeKcpConn(convId, kcp.EnetServerKick)
break
}
kcpMsg := protoEnDecode.protoEncode(protoMsg)
if kcpMsg == nil {
logger.LOG.Error("decode kcp msg is nil, convId: %v", convId)
continue
}
bin := k.encodePayloadToBin(kcpMsg)
_ = conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
_, err := conn.Write(bin)
if err != nil {
logger.LOG.Error("exit send loop, conn write err: %v, convId: %v", err, convId)
k.closeKcpConn(convId, kcp.EnetServerKick)
break
}
k.kcpSendListenMapLock.RLock()
flag := k.kcpSendListenMap[convId]
k.kcpSendListenMapLock.RUnlock()
if flag {
// 发包通知
k.kcpEventOutput <- &KcpEvent{
ConvId: convId,
EventId: KcpPacketSendNotify,
EventMessage: bin,
}
}
}
}
func (k *KcpConnectManager) rttMonitor(convId uint64) {
ticker := time.NewTicker(time.Second * 10)
for {
select {
case <-ticker.C:
k.connMapLock.RLock()
conn := k.connMap[convId]
k.connMapLock.RUnlock()
if conn == nil {
break
}
logger.LOG.Debug("convId: %v, RTO: %v, SRTT: %v, RTTVar: %v", convId, conn.GetRTO(), conn.GetSRTT(), conn.GetSRTTVar())
k.kcpEventOutput <- &KcpEvent{
ConvId: convId,
EventId: KcpConnRttNotify,
EventMessage: conn.GetSRTT(),
}
}
}
}
func (k *KcpConnectManager) closeKcpConn(convId uint64, enetType uint32) {
k.connMapLock.RLock()
conn, exist := k.connMap[convId]
k.connMapLock.RUnlock()
if !exist {
return
}
// 获取待关闭的发送管道
k.kcpRawSendChanMapLock.RLock()
kcpRawSendChan := k.kcpRawSendChanMap[convId]
k.kcpRawSendChanMapLock.RUnlock()
// 清理数据
k.connMapLock.Lock()
delete(k.connMap, convId)
k.connMapLock.Unlock()
k.kcpRawSendChanMapLock.Lock()
delete(k.kcpRawSendChanMap, convId)
k.kcpRawSendChanMapLock.Unlock()
k.kcpRecvListenMapLock.Lock()
delete(k.kcpRecvListenMap, convId)
k.kcpRecvListenMapLock.Unlock()
k.kcpSendListenMapLock.Lock()
delete(k.kcpSendListenMap, convId)
k.kcpSendListenMapLock.Unlock()
k.kcpKeyMapLock.Lock()
delete(k.kcpKeyMap, convId)
k.kcpKeyMapLock.Unlock()
// 关闭连接
conn.SendEnetNotify(&kcp.Enet{
ConnType: kcp.ConnEnetFin,
EnetType: enetType,
})
_ = conn.Close()
// 关闭发送管道
close(kcpRawSendChan)
// 连接关闭通知
k.kcpEventOutput <- &KcpEvent{
ConvId: convId,
EventId: KcpConnCloseNotify,
}
}
func (k *KcpConnectManager) closeAllKcpConn() {
closeConnList := make([]*kcp.UDPSession, 0)
k.connMapLock.RLock()
for _, v := range k.connMap {
closeConnList = append(closeConnList, v)
}
k.connMapLock.RUnlock()
for _, v := range closeConnList {
k.closeKcpConn(v.GetConv(), kcp.EnetServerShutdown)
}
}

View File

@@ -0,0 +1,187 @@
package net
import (
"bytes"
"encoding/binary"
"flswld.com/common/utils/endec"
"flswld.com/logger"
)
/*
原神KCP协议(带*为xor加密数据)
0 1 2 4 8(字节)
+---------------------------------------------------------------------------------------+
| conv |
+---------------------------------------------------------------------------------------+
| cmd | frg | wnd | ts |
+---------------------------------------------------------------------------------------+
| sn | una |
+---------------------------------------------------------------------------------------+
| len | 0X4567* | apiId* |
+---------------------------------------------------------------------------------------+
| headLen* | payloadLen* | head* |
+---------------------------------------------------------------------------------------+
| payload* | 0X89AB* |
+---------------------------------------------------------------------------------------+
*/
type KcpMsg struct {
ConvId uint64
ApiId uint16
HeadData []byte
ProtoData []byte
}
func (k *KcpConnectManager) decodeBinToPayload(data []byte, convId uint64, kcpMsgList *[]*KcpMsg) {
// xor解密
k.kcpKeyMapLock.RLock()
xorKey, exist := k.kcpKeyMap[convId]
k.kcpKeyMapLock.RUnlock()
if !exist {
logger.LOG.Error("kcp xor key not exist, convId: %v", convId)
return
}
endec.Xor(data, xorKey.decKey)
k.decodeRecur(data, convId, kcpMsgList)
}
func (k *KcpConnectManager) decodeRecur(data []byte, convId uint64, kcpMsgList *[]*KcpMsg) {
// 长度太短
if len(data) < 12 {
logger.LOG.Debug("packet len less 12 byte")
return
}
// 头部标志错误
if data[0] != 0x45 || data[1] != 0x67 {
logger.LOG.Error("packet head magic 0x4567 error")
return
}
// 协议号
apiIdByteSlice := make([]byte, 8)
apiIdByteSlice[6] = data[2]
apiIdByteSlice[7] = data[3]
apiIdBuffer := bytes.NewBuffer(apiIdByteSlice)
var apiId int64
err := binary.Read(apiIdBuffer, binary.BigEndian, &apiId)
if err != nil {
logger.LOG.Error("packet api id parse fail: %v", err)
return
}
// 头部长度
headLenByteSlice := make([]byte, 8)
headLenByteSlice[6] = data[4]
headLenByteSlice[7] = data[5]
headLenBuffer := bytes.NewBuffer(headLenByteSlice)
var headLen int64
err = binary.Read(headLenBuffer, binary.BigEndian, &headLen)
if err != nil {
logger.LOG.Error("packet head len parse fail: %v", err)
return
}
// proto长度
protoLenByteSlice := make([]byte, 8)
protoLenByteSlice[4] = data[6]
protoLenByteSlice[5] = data[7]
protoLenByteSlice[6] = data[8]
protoLenByteSlice[7] = data[9]
protoLenBuffer := bytes.NewBuffer(protoLenByteSlice)
var protoLen int64
err = binary.Read(protoLenBuffer, binary.BigEndian, &protoLen)
if err != nil {
logger.LOG.Error("packet proto len parse fail: %v", err)
return
}
// 检查最小长度
if len(data) < int(headLen+protoLen)+12 {
logger.LOG.Error("packet len error")
return
}
// 尾部标志错误
if data[headLen+protoLen+10] != 0x89 || data[headLen+protoLen+11] != 0xAB {
logger.LOG.Error("packet tail magic 0x89AB error")
return
}
// 判断是否有不止一个包
haveMoreData := false
if len(data) > int(headLen+protoLen)+12 {
haveMoreData = true
}
// 头部数据
headData := data[10 : 10+headLen]
// proto数据
protoData := data[10+headLen : 10+headLen+protoLen]
// 返回数据
kcpMsg := new(KcpMsg)
kcpMsg.ConvId = convId
kcpMsg.ApiId = uint16(apiId)
//kcpMsg.HeadData = make([]byte, len(headData))
//copy(kcpMsg.HeadData, headData)
//kcpMsg.ProtoData = make([]byte, len(protoData))
//copy(kcpMsg.ProtoData, protoData)
kcpMsg.HeadData = headData
kcpMsg.ProtoData = protoData
*kcpMsgList = append(*kcpMsgList, kcpMsg)
// 递归解析
if haveMoreData {
k.decodeRecur(data[int(headLen+protoLen)+12:], convId, kcpMsgList)
}
}
func (k *KcpConnectManager) encodePayloadToBin(kcpMsg *KcpMsg) (bin []byte) {
if kcpMsg.HeadData == nil {
kcpMsg.HeadData = make([]byte, 0)
}
if kcpMsg.ProtoData == nil {
kcpMsg.ProtoData = make([]byte, 0)
}
bin = make([]byte, len(kcpMsg.HeadData)+len(kcpMsg.ProtoData)+12)
// 头部标志
bin[0] = 0x45
bin[1] = 0x67
// 协议号
apiIdBuffer := bytes.NewBuffer([]byte{})
err := binary.Write(apiIdBuffer, binary.BigEndian, kcpMsg.ApiId)
if err != nil {
logger.LOG.Error("api id encode err: %v", err)
return nil
}
bin[2] = (apiIdBuffer.Bytes())[0]
bin[3] = (apiIdBuffer.Bytes())[1]
// 头部长度
headLenBuffer := bytes.NewBuffer([]byte{})
err = binary.Write(headLenBuffer, binary.BigEndian, uint16(len(kcpMsg.HeadData)))
if err != nil {
logger.LOG.Error("head len encode err: %v", err)
return nil
}
bin[4] = (headLenBuffer.Bytes())[0]
bin[5] = (headLenBuffer.Bytes())[1]
// proto长度
protoLenBuffer := bytes.NewBuffer([]byte{})
err = binary.Write(protoLenBuffer, binary.BigEndian, uint32(len(kcpMsg.ProtoData)))
if err != nil {
logger.LOG.Error("proto len encode err: %v", err)
return nil
}
bin[6] = (protoLenBuffer.Bytes())[0]
bin[7] = (protoLenBuffer.Bytes())[1]
bin[8] = (protoLenBuffer.Bytes())[2]
bin[9] = (protoLenBuffer.Bytes())[3]
// 头部数据
copy(bin[10:], kcpMsg.HeadData)
// proto数据
copy(bin[10+len(kcpMsg.HeadData):], kcpMsg.ProtoData)
// 尾部标志
bin[len(bin)-2] = 0x89
bin[len(bin)-1] = 0xAB
// xor加密
k.kcpKeyMapLock.RLock()
xorKey, exist := k.kcpKeyMap[kcpMsg.ConvId]
k.kcpKeyMapLock.RUnlock()
if !exist {
logger.LOG.Error("kcp xor key not exist, convId: %v", kcpMsg.ConvId)
return
}
endec.Xor(bin, xorKey.encKey)
return bin
}

134
gate-hk4e/net/kcp_event.go Normal file
View File

@@ -0,0 +1,134 @@
package net
import "flswld.com/logger"
const (
KcpXorKeyChange = iota
KcpPacketRecvListen
KcpPacketSendListen
KcpConnForceClose
KcpAllConnForceClose
KcpGateOpenState
KcpPacketRecvNotify
KcpPacketSendNotify
KcpConnCloseNotify
KcpConnEstNotify
KcpConnRttNotify
KcpConnAddrChangeNotify
)
type KcpEvent struct {
ConvId uint64
EventId int
EventMessage any
}
func (k *KcpConnectManager) eventHandle() {
// 事件处理
for {
event := <-k.kcpEventInput
logger.LOG.Info("kcp manager recv event, ConvId: %v, EventId: %v, EventMessage: %v", event.ConvId, event.EventId, event.EventMessage)
switch event.EventId {
case KcpXorKeyChange:
// XOR密钥切换
k.connMapLock.RLock()
_, exist := k.connMap[event.ConvId]
k.connMapLock.RUnlock()
if !exist {
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
continue
}
flag, ok := event.EventMessage.(string)
if !ok {
logger.LOG.Error("event KcpXorKeyChange msg type error")
continue
}
if flag == "ENC" {
k.kcpKeyMapLock.Lock()
k.kcpKeyMap[event.ConvId].encKey = k.secretKey
k.kcpKeyMapLock.Unlock()
} else if flag == "DEC" {
k.kcpKeyMapLock.Lock()
k.kcpKeyMap[event.ConvId].decKey = k.secretKey
k.kcpKeyMapLock.Unlock()
}
case KcpPacketRecvListen:
// 收包监听
k.connMapLock.RLock()
_, exist := k.connMap[event.ConvId]
k.connMapLock.RUnlock()
if !exist {
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
continue
}
flag, ok := event.EventMessage.(string)
if !ok {
logger.LOG.Error("event KcpXorKeyChange msg type error")
continue
}
if flag == "Enable" {
k.kcpRecvListenMapLock.Lock()
k.kcpRecvListenMap[event.ConvId] = true
k.kcpRecvListenMapLock.Unlock()
} else if flag == "Disable" {
k.kcpRecvListenMapLock.Lock()
k.kcpRecvListenMap[event.ConvId] = false
k.kcpRecvListenMapLock.Unlock()
}
case KcpPacketSendListen:
// 发包监听
k.connMapLock.RLock()
_, exist := k.connMap[event.ConvId]
k.connMapLock.RUnlock()
if !exist {
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
continue
}
flag, ok := event.EventMessage.(string)
if !ok {
logger.LOG.Error("event KcpXorKeyChange msg type error")
continue
}
if flag == "Enable" {
k.kcpSendListenMapLock.Lock()
k.kcpSendListenMap[event.ConvId] = true
k.kcpSendListenMapLock.Unlock()
} else if flag == "Disable" {
k.kcpSendListenMapLock.Lock()
k.kcpSendListenMap[event.ConvId] = false
k.kcpSendListenMapLock.Unlock()
}
case KcpConnForceClose:
// 强制关闭某个连接
k.connMapLock.RLock()
_, exist := k.connMap[event.ConvId]
k.connMapLock.RUnlock()
if !exist {
logger.LOG.Error("conn not exist, convId: %v", event.ConvId)
continue
}
reason, ok := event.EventMessage.(uint32)
if !ok {
logger.LOG.Error("event KcpConnForceClose msg type error")
continue
}
k.closeKcpConn(event.ConvId, reason)
logger.LOG.Info("conn has been force close, convId: %v", event.ConvId)
case KcpAllConnForceClose:
// 强制关闭所有连接
k.closeAllKcpConn()
logger.LOG.Info("all conn has been force close")
case KcpGateOpenState:
// 改变网关开放状态
openState, ok := event.EventMessage.(bool)
if !ok {
logger.LOG.Error("event KcpGateOpenState msg type error")
continue
}
k.openState = openState
if openState == false {
k.closeAllKcpConn()
}
}
}
}

View File

@@ -0,0 +1,160 @@
package net
import (
"flswld.com/gate-hk4e-api/proto"
"flswld.com/logger"
pb "google.golang.org/protobuf/proto"
)
type ProtoEnDecode struct {
apiProtoMap *proto.ApiProtoMap
}
func NewProtoEnDecode() (r *ProtoEnDecode) {
r = new(ProtoEnDecode)
r.apiProtoMap = proto.NewApiProtoMap()
return r
}
type ProtoMsg struct {
ConvId uint64
ApiId uint16
HeadMessage *proto.PacketHead
PayloadMessage pb.Message
}
type ProtoMessage struct {
apiId uint16
message pb.Message
}
func (p *ProtoEnDecode) protoDecode(kcpMsg *KcpMsg) (protoMsgList []*ProtoMsg) {
protoMsgList = make([]*ProtoMsg, 0)
protoMsg := new(ProtoMsg)
protoMsg.ConvId = kcpMsg.ConvId
protoMsg.ApiId = kcpMsg.ApiId
// head msg
if kcpMsg.HeadData != nil && len(kcpMsg.HeadData) != 0 {
headMsg := new(proto.PacketHead)
err := pb.Unmarshal(kcpMsg.HeadData, headMsg)
if err != nil {
logger.LOG.Error("unmarshal head data err: %v", err)
return protoMsgList
}
protoMsg.HeadMessage = headMsg
} else {
protoMsg.HeadMessage = nil
}
// payload msg
protoMessageList := make([]*ProtoMessage, 0)
p.protoDecodePayloadCore(kcpMsg.ApiId, kcpMsg.ProtoData, &protoMessageList)
if len(protoMessageList) == 0 {
logger.LOG.Error("decode proto object is nil")
return protoMsgList
}
if kcpMsg.ApiId == proto.ApiUnionCmdNotify {
for _, protoMessage := range protoMessageList {
msg := new(ProtoMsg)
msg.ConvId = kcpMsg.ConvId
msg.ApiId = protoMessage.apiId
msg.HeadMessage = protoMsg.HeadMessage
msg.PayloadMessage = protoMessage.message
//logger.LOG.Debug("[recv] union proto msg, convId: %v, apiId: %v", msg.ConvId, msg.ApiId)
if protoMessage.apiId == proto.ApiUnionCmdNotify {
// 聚合消息自身不再往后发送
continue
}
//logger.LOG.Debug("[recv] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
protoMsgList = append(protoMsgList, msg)
}
// 聚合消息自身不再往后发送
return protoMsgList
} else {
protoMsg.PayloadMessage = protoMessageList[0].message
}
//logger.LOG.Debug("[recv] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
protoMsgList = append(protoMsgList, protoMsg)
return protoMsgList
}
func (p *ProtoEnDecode) protoDecodePayloadCore(apiId uint16, protoData []byte, protoMessageList *[]*ProtoMessage) {
protoObj := p.decodePayloadToProto(apiId, protoData)
if protoObj == nil {
logger.LOG.Error("decode proto object is nil")
return
}
if apiId == proto.ApiUnionCmdNotify {
// 处理聚合消息
unionCmdNotify, ok := protoObj.(*proto.UnionCmdNotify)
if !ok {
logger.LOG.Error("parse union cmd error")
return
}
for _, cmd := range unionCmdNotify.GetCmdList() {
p.protoDecodePayloadCore(uint16(cmd.MessageId), cmd.Body, protoMessageList)
}
}
*protoMessageList = append(*protoMessageList, &ProtoMessage{
apiId: apiId,
message: protoObj,
})
}
func (p *ProtoEnDecode) protoEncode(protoMsg *ProtoMsg) (kcpMsg *KcpMsg) {
//logger.LOG.Debug("[send] proto msg, convId: %v, apiId: %v, headMsg: %v", protoMsg.ConvId, protoMsg.ApiId, protoMsg.HeadMessage)
kcpMsg = new(KcpMsg)
kcpMsg.ConvId = protoMsg.ConvId
kcpMsg.ApiId = protoMsg.ApiId
// head msg
if protoMsg.HeadMessage != nil {
headData, err := pb.Marshal(protoMsg.HeadMessage)
if err != nil {
logger.LOG.Error("marshal head data err: %v", err)
return nil
}
kcpMsg.HeadData = headData
} else {
kcpMsg.HeadData = nil
}
// payload msg
if protoMsg.PayloadMessage != nil {
apiId, protoData := p.encodeProtoToPayload(protoMsg.PayloadMessage)
if apiId == 0 || protoData == nil {
logger.LOG.Error("encode proto data is nil")
return nil
}
if apiId != 65535 && apiId != protoMsg.ApiId {
logger.LOG.Error("api id is not match with proto obj, src api id: %v, found api id: %v", protoMsg.ApiId, apiId)
return nil
}
kcpMsg.ProtoData = protoData
} else {
kcpMsg.ProtoData = nil
}
return kcpMsg
}
func (p *ProtoEnDecode) decodePayloadToProto(apiId uint16, protoData []byte) (protoObj pb.Message) {
protoObj = p.apiProtoMap.GetProtoObjByApiId(apiId)
if protoObj == nil {
logger.LOG.Error("get new proto object is nil")
return nil
}
err := pb.Unmarshal(protoData, protoObj)
if err != nil {
logger.LOG.Error("unmarshal proto data err: %v", err)
return nil
}
return protoObj
}
func (p *ProtoEnDecode) encodeProtoToPayload(protoObj pb.Message) (apiId uint16, protoData []byte) {
apiId = p.apiProtoMap.GetApiIdByProtoObj(protoObj)
var err error = nil
protoData, err = pb.Marshal(protoObj)
if err != nil {
logger.LOG.Error("marshal proto object err: %v", err)
return 0, nil
}
return apiId, protoData
}