/
packet.go
144 lines (129 loc) · 2.92 KB
/
packet.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package packet
import (
"bytes"
"compress/zlib"
"encoding/binary"
"encoding/json"
"github.com/andybalholm/brotli"
log "github.com/sirupsen/logrus"
"io"
)
const (
Plain = iota
Popularity
Zlib
Brotli
)
const (
_ = iota
_
HeartBeat
HeartBeatResponse
_
Notification
_
RoomEnter
RoomEnterResponse
)
type Packet struct {
PacketLength int // PacketLength 在 build 时会计算
HeaderLength int // HeaderLength 大概是固定值 16
ProtocolVersion uint16
Operation uint32
SequenceID int
Body []byte
}
func NewPacket(protocolVersion uint16, operation uint32, body []byte) Packet {
return Packet{
ProtocolVersion: protocolVersion,
Operation: operation,
Body: body,
}
}
// NewPlainPacket 构造新的 Plain 包
// 对外暴露的方法中 operation 全部使用int
func NewPlainPacket(operation int, body []byte) Packet {
return NewPacket(Plain, uint32(operation), body)
}
func NewPacketFromBytes(data []byte) Packet {
packLen := binary.BigEndian.Uint32(data[0:4])
// 校验包长度
if int(packLen) != len(data) {
log.Error("error packet")
}
pv := binary.BigEndian.Uint16(data[6:8])
op := binary.BigEndian.Uint32(data[8:12])
body := data[16:packLen]
packet := NewPacket(pv, op, body)
return packet
}
func (p Packet) Parse() []Packet {
switch p.ProtocolVersion {
case Popularity:
fallthrough
case Plain:
return []Packet{p}
case Zlib:
z, err := zlibParser(p.Body)
if err != nil {
log.Error("zlib error", err)
}
return Slice(z)
case Brotli:
b, err := brotliParser(p.Body)
if err != nil {
log.Error("brotli error", err)
}
return Slice(b)
default:
log.Error("unknown protocolVersion")
}
return nil
}
func (p *Packet) Unmarshal(v interface{}) error {
return json.Unmarshal(p.Body, v)
}
func (p *Packet) Build() []byte {
rawBuf := []byte{0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
binary.BigEndian.PutUint16(rawBuf[6:], p.ProtocolVersion)
binary.BigEndian.PutUint32(rawBuf[8:], p.Operation)
rawBuf = append(rawBuf, p.Body...)
binary.BigEndian.PutUint32(rawBuf, uint32(len(rawBuf)))
return rawBuf
}
// DecodePacket Decode
func DecodePacket(data []byte) Packet {
return NewPacketFromBytes(data)
}
// EncodePacket Encode
func EncodePacket(packet Packet) []byte {
return packet.Build()
}
func Slice(data []byte) []Packet {
var packets []Packet
total := len(data)
cursor := 0
for cursor < total {
packLen := int(binary.BigEndian.Uint32(data[cursor : cursor+4]))
packets = append(packets, DecodePacket(data[cursor:cursor+packLen]))
cursor += packLen
}
return packets
}
func zlibParser(b []byte) ([]byte, error) {
var rdBuf []byte
zr, err := zlib.NewReader(bytes.NewReader(b))
if err != nil {
return nil, err
}
rdBuf, err = io.ReadAll(zr)
return rdBuf, nil
}
func brotliParser(b []byte) ([]byte, error) {
zr := brotli.NewReader(bytes.NewReader(b))
rdBuf, err := io.ReadAll(zr)
if err != nil {
return nil, err
}
return rdBuf, nil
}