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
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
|
|
}
|
|
}
|