Files
blivedm-go/packet/packet.go
Akegarasu ad7bc5fe32 fix #23
2024-10-30 16:46:58 +08:00

164 lines
3.3 KiB
Go

package packet
import (
"bytes"
"compress/zlib"
"encoding/binary"
"encoding/json"
"io"
"github.com/andybalholm/brotli"
log "github.com/sirupsen/logrus"
)
const (
Plain = iota
Popularity
Zlib
Brotli
)
const (
HandShake = iota
HandShakeResponse
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(1, uint32(operation), body)
}
func NewPacketFromBytes(data []byte) Packet {
if len(data) == 0 {
log.Error("error packet")
return Packet{ProtocolVersion: 1, Operation: uint32(3), Body: make([]byte, 0)}
}
packLen := binary.BigEndian.Uint32(data[0:4])
if int(packLen) == 0 || int(packLen) != len(data) {
log.Error("error packet")
return Packet{ProtocolVersion: 1, Operation: uint32(3), Body: make([]byte, 0)}
}
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 {
// default packet with some constants
// raw header length: buf[5] = 16
// seq: buf[16] = 1
rawBuf := []byte{0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
// protocol version
binary.BigEndian.PutUint16(rawBuf[6:], p.ProtocolVersion)
// operation code
binary.BigEndian.PutUint32(rawBuf[8:], p.Operation)
// append payload
rawBuf = append(rawBuf, p.Body...)
// payload length
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
}