package huya import ( "fmt" "math/rand" "huya-go/internal/taf" ) const ( WSSCmdNull int32 = 0 WSSCmdRegisterReq int32 = 1 WSSCmdRegisterRsp int32 = 2 WSSCmdWupReq int32 = 3 WSSCmdWupRsp int32 = 4 WSSCmdHeartBeat int32 = 5 WSSCmdHeartBeatAck int32 = 6 WSSCmdMsgPushReq int32 = 7 WSSCmdDeregisterReq int32 = 8 WSSCmdDeregisterRsp int32 = 9 WSSCmdVerifyCookieReq int32 = 10 WSSCmdVerifyCookieRsp int32 = 11 WSSCmdVerifyHuyaTokenReq int32 = 12 WSSCmdVerifyHuyaTokenRsp int32 = 13 WSSCmdUnverifyReq int32 = 14 WSSCmdUnverifyRsp int32 = 15 WSSCmdRegisterGroupReq int32 = 16 WSSCmdRegisterGroupRsp int32 = 17 WSSCmdUnregisterGroupReq int32 = 18 WSSCmdUnregisterGroupRsp int32 = 19 WSSCmdHeartBeatReq int32 = 20 WSSCmdHeartBeatRsp int32 = 21 WSSCmdMsgPushReqV2 int32 = 22 WSSCmdUpdateUserExpsReq int32 = 23 WSSCmdUpdateUserExpsRsp int32 = 24 WSSCmdUpdateUserInfoReq int32 = 33 WSSCmdUpdateUserInfoRsp int32 = 34 WSSCmdMsgAckReq int32 = 35 WSSCmdMsgAckRsp int32 = 36 WSSCmdS2CRpcReq int32 = 40 WSSCmdC2SRpcRsp int32 = 41 WSSCmdS2CRpcRspRsp int32 = 42 WSSCmdSignalUpgradeReq int32 = 105 WSSCmdSignalUpgradeRsp int32 = 106 defaultWSSTraceEnableValue = 0 ) // WSSCommand 是浏览器 JS 里的 HUYA.WebSocketCommand。 // // 注意:这不是旧版的 6 字节自定义头。浏览器实际把这个 TAF/JCE // 结构直接作为 WebSocket binary payload 发送。 type WSSCommand struct { CmdType int32 Data []byte RequestID int64 TraceID string EncryptType int32 Time int64 MD5 string } func (c *WSSCommand) WriteTo(w *taf.Writer) error { if err := w.WriteInt32(0, int64(c.CmdType)); err != nil { return err } if err := w.WriteBytes(1, c.Data); err != nil { return err } if err := w.WriteInt64(2, c.RequestID); err != nil { return err } if err := w.WriteString(3, c.TraceID); err != nil { return err } if err := w.WriteInt32(4, int64(c.EncryptType)); err != nil { return err } if err := w.WriteInt64(5, c.Time); err != nil { return err } return w.WriteString(6, c.MD5) } func (c *WSSCommand) ReadFrom(r *taf.Reader) error { var err error if c.CmdType, err = r.ReadInt32(0, false, c.CmdType); err != nil { return err } if c.Data, err = r.ReadBytes(1, false, c.Data); err != nil { return err } if c.RequestID, err = r.ReadInt64(2, false, c.RequestID); err != nil { return err } if c.TraceID, err = r.ReadString(3, false, c.TraceID); err != nil { return err } if c.EncryptType, err = r.ReadInt32(4, false, c.EncryptType); err != nil { return err } if c.Time, err = r.ReadInt64(5, false, c.Time); err != nil { return err } c.MD5, err = r.ReadString(6, false, c.MD5) return err } func (c WSSCommand) Encode() ([]byte, error) { w := taf.NewWriter() if err := c.WriteTo(w); err != nil { return nil, err } return append([]byte(nil), w.Bytes()...), nil } func DecodeWSSCommand(data []byte) (WSSCommand, error) { var cmd WSSCommand if len(data) == 0 { return cmd, fmt.Errorf("wss: 空消息") } if err := cmd.ReadFrom(taf.NewReader(data)); err != nil { return cmd, err } return cmd, nil } func EncodeWSSCommand(cmdType int32, data []byte, traceID string) ([]byte, error) { return WSSCommand{ CmdType: cmdType, Data: append([]byte(nil), data...), TraceID: traceID, }.Encode() } func encodeWSSStructCommand(cmdType int32, value taf.Marshaler) ([]byte, error) { w := taf.NewWriter() if value != nil { if err := value.WriteTo(w); err != nil { return nil, err } } return EncodeWSSCommand(cmdType, w.Bytes(), "") } func NewWSSCommandTrace() string { trace := lowerHex16(rand.Uint64()) return fmt.Sprintf("%s:%s:0:%d", trace, trace, defaultWSSTraceEnableValue) }