114 lines
2.8 KiB
Go
114 lines
2.8 KiB
Go
package huya
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/rand"
|
|
)
|
|
|
|
const (
|
|
WSSCommandRPCRequest byte = 0x03
|
|
WSSCommandRPCResponse byte = 0x04
|
|
WSSCommandAuth byte = 0x0a
|
|
WSSCommandHeartbeatSend byte = 0x10
|
|
WSSCommandHeartbeatRecv byte = 0x11
|
|
WSSCommandConfirmSend byte = 0x17
|
|
WSSCommandRegister byte = 0x21
|
|
|
|
wssSeqHeartbeat uint32 = 0x1d00000d
|
|
wssSeqWSLaunch uint32 = 0x1d000078
|
|
wssSeqGetConfig uint32 = 0x1d000076
|
|
wssSeqRegister uint32 = 0x1d00003c
|
|
wssSeqConfirm uint32 = 0x1d000002
|
|
wssSeqBusiness uint32 = 0x1d000106
|
|
)
|
|
|
|
var (
|
|
wssTailBytes = []byte{0x2c, 0x36, 0x00, 0x4c, 0x5c, 0x66, 0x00}
|
|
wssBigTailSuffix = []byte{0x4c, 0x5c, 0x66, 0x00}
|
|
)
|
|
|
|
// WSSMessage 是虎牙 WebSocketCommand 的 Go 表达。
|
|
//
|
|
// 外层格式来自浏览器/参考项目:
|
|
//
|
|
// 1B version(0) + 1B command + 4B sequence + body
|
|
type WSSMessage struct {
|
|
Command byte
|
|
Sequence uint32
|
|
Body []byte
|
|
}
|
|
|
|
func (m WSSMessage) Encode() []byte {
|
|
out := make([]byte, 6+len(m.Body))
|
|
out[0] = 0
|
|
out[1] = m.Command
|
|
binary.BigEndian.PutUint32(out[2:6], m.Sequence)
|
|
copy(out[6:], m.Body)
|
|
return out
|
|
}
|
|
|
|
func DecodeWSSMessage(data []byte) (WSSMessage, error) {
|
|
if len(data) < 6 {
|
|
return WSSMessage{}, fmt.Errorf("wss: 消息太短: %d", len(data))
|
|
}
|
|
return WSSMessage{
|
|
Command: data[1],
|
|
Sequence: binary.BigEndian.Uint32(data[2:6]),
|
|
Body: append([]byte(nil), data[6:]...),
|
|
}, nil
|
|
}
|
|
|
|
func encodeWSSRPCBody(wupData []byte) []byte {
|
|
if len(wupData) < 4 {
|
|
out := append([]byte{}, wupData...)
|
|
return append(out, wssTailBytes...)
|
|
}
|
|
declaredLen := int(binary.BigEndian.Uint32(wupData[:4]))
|
|
wupBody := wupData
|
|
if declaredLen == len(wupData) {
|
|
wupBody = wupData[4:]
|
|
}
|
|
if len(wupBody) <= 0xff {
|
|
out := append([]byte{}, wupData...)
|
|
return append(out, wssTailBytes...)
|
|
}
|
|
|
|
trace := NewWSSBigTailTrace()
|
|
packetLen := len(wupData)
|
|
out := make([]byte, 0, 1+4+len(wupBody)+len(trace))
|
|
out = append(out, byte(packetLen&0xff))
|
|
var lenBuf [4]byte
|
|
binary.BigEndian.PutUint32(lenBuf[:], uint32(packetLen))
|
|
out = append(out, lenBuf[:]...)
|
|
out = append(out, wupBody...)
|
|
out = append(out, trace...)
|
|
return out
|
|
}
|
|
|
|
func extractWUPFromWSSBody(body []byte) []byte {
|
|
if len(body) < 5 {
|
|
return body
|
|
}
|
|
// 大包格式: [1B prefix][4B wup_len][裸 WUP body][tail]
|
|
wupLen := int(binary.BigEndian.Uint32(body[1:5]))
|
|
if 5+wupLen <= len(body) && len(body) >= 7 && body[5] == 0x10 && body[6] == 0x03 {
|
|
return body[5 : 5+wupLen]
|
|
}
|
|
// 小包格式: [4B total_len][WUP body][tail]
|
|
totalLen := int(binary.BigEndian.Uint32(body[:4]))
|
|
if 8 <= totalLen && totalLen <= len(body) && body[4] == 0x10 && body[5] == 0x03 {
|
|
return body[:totalLen]
|
|
}
|
|
if 5+wupLen <= len(body) {
|
|
return body[5 : 5+wupLen]
|
|
}
|
|
return body
|
|
}
|
|
|
|
func NewWSSBigTailTrace() []byte {
|
|
trace := lowerHex16(rand.Uint64())
|
|
out := []byte(",6%" + trace + ":" + trace + ":0:3")
|
|
return append(out, wssBigTailSuffix...)
|
|
}
|