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