You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.5 KiB
Go

package douyu
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/gorilla/websocket"
"github.com/pkg/errors"
"live-gateway/ws"
)
const (
wsPackageLen = 4
wsMsgTypeLen = 2
wsSecretLen = 1
wsReservedLen = 1
wsEndingLen = 1
)
var _ ws.Packer = (*PackDouyu)(nil)
// PackDouyu douyu packer
//
// | segment | type | size | offset | remark |
// | ---------- | ------ | ------- | -------| ------------------------------------------- |
// | `packageLen` | uint32 | 4 | 0 | 消息长度 4字节 |
// | `packageLen` | uint32 | 4 | 4 | 消息长度 4字节 |
// | `msgType` | uint16 | 2 | 8 | 消息类型 2字节 小端整数 |
// | `secret` | byte | 1 | 10 | 加密字段 1字节 暂时未用,默认为 0 |
// | `reserved` | byte | 1 | 11 | 1 |
// | `data` | []byte | dynamic | 12 | :数据内容,结尾'\0' |
// WsEntry -> ws.Entry#Raw
type PackDouyu struct {
}
func NewPackDouyu() ws.Packer {
return &PackDouyu{}
}
func (*PackDouyu) byteOrder() binary.ByteOrder {
return binary.LittleEndian
}
// Unpack unpacks douyu.WsEntry to ws.Entry
func (p *PackDouyu) Unpack(v interface{}) (*ws.Entry, error) {
result := &ws.Entry{
MessageType: websocket.BinaryMessage,
}
// v must be bilibili.WsEntry
entry, ok := v.(*WsEntry)
if !ok {
return nil, fmt.Errorf("[Pack-Douyu] 写入值类型必须为 %T", WsEntry{})
}
var err error
length := wsPackageLen + wsMsgTypeLen + wsSecretLen +
wsReservedLen + len(entry.data) + wsEndingLen // 8+len(data)+1
buffer := bytes.NewBuffer([]byte{})
byteOrder := p.byteOrder()
err = binary.Write(buffer, byteOrder, int32(length))
err = binary.Write(buffer, byteOrder, int32(length))
err = binary.Write(buffer, byteOrder, entry.msgType)
err = binary.Write(buffer, byteOrder, entry.secret)
err = binary.Write(buffer, byteOrder, entry.reserved)
err = binary.Write(buffer, byteOrder, entry.data)
err = binary.Write(buffer, byteOrder, EndCharacter)
if err != nil {
return nil, err
}
result.Raw = buffer.Bytes()
return result, nil
}
// Pack packs ws.Entry to douyu.WsEntry
func (p *PackDouyu) Pack(entry *ws.Entry) (interface{}, error) {
defer func() {
if err := recover(); err != nil {
}
}()
if entry.MessageType != websocket.BinaryMessage {
return nil, errors.New("err of msg")
}
var (
offsetLen = wsPackageLen
offsetMsgType = offsetLen + offsetLen
offsetSecret = offsetMsgType + wsMsgTypeLen
offsetReserved = offsetSecret + wsSecretLen
offsetData = offsetReserved + wsReservedLen
)
byteOrder := p.byteOrder()
raw := entry.Raw
l := int(byteOrder.Uint32(raw[:offsetLen])) + wsPackageLen
if len(raw) > l {
// 粘包
var slice []*ws.Entry
for len(raw) > 0 {
tmp := &ws.Entry{
MessageType: entry.MessageType,
}
length := int(byteOrder.Uint32(raw[:offsetLen])) + wsPackageLen
var ll = length
if len(raw) < length {
ll = len(raw)
}
tmp.Raw = raw[:ll]
raw = raw[ll:]
slice = append(slice, tmp)
}
return slice, nil
} else {
// 独立包
ent := &WsEntry{}
ent.msgType = byteOrder.Uint16(raw[offsetMsgType : offsetMsgType+wsMsgTypeLen])
ent.secret = raw[offsetSecret]
ent.reserved = raw[offsetReserved]
endOffset := len(entry.Raw)
if entry.Raw[endOffset-1] == 0 {
endOffset -= 1
}
ent.data = raw[offsetData:endOffset]
return ent, nil
}
}