- 新增 launch.queryHttpDns:类型定义 + HTTPClient.QueryHttpDns + WSSClient.resolveHost(TTL 缓存、多 host 轮询、失败回退默认 host);Host 留空或等于历史默认值即视为自动解析 - WSS 握手 baseinfo 补 tag5=exp 与 tag10 空 customHeaders;UpdateUserExpsReq(cmd23) 改为回传 getConfig 的版本 map(缓存供重连复用) - 新增 launch.pingSignal:HTTP 预热改走 pingSignal,WSS 预热在建连后探测业务通道(失败仅记日志) - UserPrizeInfo 补 tag12 orderId/tag14 图标/tag16 prizeId/tag17 shopItemId/tag19 itemId/tag20 ext/tag21 exchangeDate,前端复盘表加订单号列 - taf 补 WriteListString/ReadListString/ReadMapStringInt64/ReadMapStringStruct - 新增 internal/huya/launch_test.go:用抓包真实报文做字节级夹具(baseinfo 122B、queryHttpDns 请求 93B、记录 308B 等) - CLI -wss-host 默认改为留空;GUI 设置支持留空并给出占位提示;README/WSS_NOTES 同步协议细节
248 lines
5.4 KiB
Go
248 lines
5.4 KiB
Go
package taf
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
// Writer 负责按 TAF/JCE 格式编码字段。
|
|
type Writer struct {
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func NewWriter() *Writer {
|
|
return &Writer{}
|
|
}
|
|
|
|
func (w *Writer) Bytes() []byte {
|
|
return w.buf.Bytes()
|
|
}
|
|
|
|
func (w *Writer) WriteHead(tag int, typ Type) error {
|
|
if tag < 0 || tag > 255 {
|
|
return fmt.Errorf("taf: tag 超出范围: %d", tag)
|
|
}
|
|
if tag < 15 {
|
|
return w.buf.WriteByte(byte(tag<<4) | byte(typ))
|
|
}
|
|
if err := w.buf.WriteByte(0xf0 | byte(typ)); err != nil {
|
|
return err
|
|
}
|
|
return w.buf.WriteByte(byte(tag))
|
|
}
|
|
|
|
func (w *Writer) WriteInt8(tag int, value int64) error {
|
|
if value == 0 {
|
|
return w.WriteHead(tag, TypeZero)
|
|
}
|
|
if value < math.MinInt8 || value > math.MaxInt8 {
|
|
return fmt.Errorf("taf: int8 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt8); err != nil {
|
|
return err
|
|
}
|
|
return w.buf.WriteByte(byte(int8(value)))
|
|
}
|
|
|
|
func (w *Writer) WriteInt16(tag int, value int64) error {
|
|
if value >= math.MinInt8 && value <= math.MaxInt8 {
|
|
return w.WriteInt8(tag, value)
|
|
}
|
|
if value < math.MinInt16 || value > math.MaxInt16 {
|
|
return fmt.Errorf("taf: int16 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt16); err != nil {
|
|
return err
|
|
}
|
|
var b [2]byte
|
|
binary.BigEndian.PutUint16(b[:], uint16(int16(value)))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteInt32(tag int, value int64) error {
|
|
if value >= math.MinInt16 && value <= math.MaxInt16 {
|
|
return w.WriteInt16(tag, value)
|
|
}
|
|
if value < math.MinInt32 || value > math.MaxInt32 {
|
|
return fmt.Errorf("taf: int32 溢出: %d", value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt32); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], uint32(int32(value)))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteInt64(tag int, value int64) error {
|
|
if value >= math.MinInt32 && value <= math.MaxInt32 {
|
|
return w.WriteInt32(tag, value)
|
|
}
|
|
if err := w.WriteHead(tag, TypeInt64); err != nil {
|
|
return err
|
|
}
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], uint64(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteBool(tag int, value bool) error {
|
|
if value {
|
|
return w.WriteInt8(tag, 1)
|
|
}
|
|
return w.WriteInt8(tag, 0)
|
|
}
|
|
|
|
func (w *Writer) WriteFloat(tag int, value float32) error {
|
|
if err := w.WriteHead(tag, TypeFloat); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], math.Float32bits(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteDouble(tag int, value float64) error {
|
|
if err := w.WriteHead(tag, TypeDouble); err != nil {
|
|
return err
|
|
}
|
|
var b [8]byte
|
|
binary.BigEndian.PutUint64(b[:], math.Float64bits(value))
|
|
_, err := w.buf.Write(b[:])
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteString(tag int, value string) error {
|
|
raw := []byte(value)
|
|
if len(raw) > math.MaxUint8 {
|
|
if err := w.WriteHead(tag, TypeString4); err != nil {
|
|
return err
|
|
}
|
|
var b [4]byte
|
|
binary.BigEndian.PutUint32(b[:], uint32(len(raw)))
|
|
if _, err := w.buf.Write(b[:]); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(raw)
|
|
return err
|
|
}
|
|
if err := w.WriteHead(tag, TypeString1); err != nil {
|
|
return err
|
|
}
|
|
if err := w.buf.WriteByte(byte(len(raw))); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(raw)
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteBytes(tag int, value []byte) error {
|
|
if err := w.WriteHead(tag, TypeSimpleList); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteHead(0, TypeInt8); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
_, err := w.buf.Write(value)
|
|
return err
|
|
}
|
|
|
|
func (w *Writer) WriteStructBegin(tag int) error {
|
|
return w.WriteHead(tag, TypeStructBegin)
|
|
}
|
|
|
|
func (w *Writer) WriteStructEnd() error {
|
|
return w.WriteHead(0, TypeStructEnd)
|
|
}
|
|
|
|
func (w *Writer) WriteStruct(tag int, value Marshaler) error {
|
|
if err := w.WriteStructBegin(tag); err != nil {
|
|
return err
|
|
}
|
|
if err := value.WriteTo(w); err != nil {
|
|
return err
|
|
}
|
|
return w.WriteStructEnd()
|
|
}
|
|
|
|
func (w *Writer) WriteMapStringString(tag int, value map[string]string) error {
|
|
if value == nil {
|
|
value = map[string]string{}
|
|
}
|
|
if err := w.WriteHead(tag, TypeMap); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
for k, v := range value {
|
|
if err := w.WriteString(0, k); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteString(1, v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Writer) WriteMapStringBytes(tag int, value map[string][]byte) error {
|
|
if value == nil {
|
|
value = map[string][]byte{}
|
|
}
|
|
if err := w.WriteHead(tag, TypeMap); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(value))); err != nil {
|
|
return err
|
|
}
|
|
for k, v := range value {
|
|
if err := w.WriteString(0, k); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteBytes(1, v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Writer) WriteListString(tag int, values []string) error {
|
|
if err := w.WriteHead(tag, TypeList); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(values))); err != nil {
|
|
return err
|
|
}
|
|
for _, value := range values {
|
|
if err := w.WriteString(0, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *Writer) WriteListStruct(tag int, values []Marshaler) error {
|
|
if err := w.WriteHead(tag, TypeList); err != nil {
|
|
return err
|
|
}
|
|
if err := w.WriteInt32(0, int64(len(values))); err != nil {
|
|
return err
|
|
}
|
|
for _, value := range values {
|
|
if err := w.WriteStruct(0, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|