Files
wechat_ipad_pro/clientsdk/mmtls/mmlonglinknet.go

250 lines
6.9 KiB
Go
Raw Normal View History

2026-02-17 13:06:23 +08:00
package mmtls
import (
"bufio"
"errors"
"fmt"
"io"
"net"
"strconv"
"time"
"xiawan/wx/clientsdk/baseutils"
)
// MMLongConnect 链接MMtls服务器
func MMLongConnect(mmInfo *MMInfo) error {
strPort := strconv.Itoa(int(mmInfo.LONGPort))
serverAddr := mmInfo.LongHost + ":" + strPort
fmt.Println("MMLongConnect serverAddr: ", serverAddr)
// mminfoDialer := "0"
// if mmInfo.Dialer != nil {
// mminfoDialer = "1"
// }
2026-02-17 13:06:23 +08:00
// 打印 mmInfo.Dialer
// fmt.Println("MMLongConnect mmInfo.Dialer: ", mminfoDialer)
// 从MMInfo获取重试参数如果未设置则使用默认值
maxRetries := mmInfo.LongConnRetryTimes
if maxRetries <= 0 {
maxRetries = 30
}
retryInterval := time.Duration(mmInfo.LongConnRetryInterval) * time.Millisecond
if retryInterval <= 0 {
retryInterval = 500 * time.Millisecond
}
connTimeout := time.Duration(mmInfo.LongConnTimeout) * time.Second
if connTimeout <= 0 {
connTimeout = 15 * time.Second
}
// 调试:打印 AllowDirectOnProxyFail 的值
fmt.Printf("MMLongConnect AllowDirectOnProxyFail: %v\n", mmInfo.AllowDirectOnProxyFail)
2026-02-17 13:06:23 +08:00
// 定义
var conn net.Conn
var err error
proxyFailed := false // 标记代理是否已经失败过
for i := 0; i < maxRetries; i++ {
// 如果有代理且代理没有被标记为失败,尝试代理连接
if mmInfo.Dialer != nil && !proxyFailed {
// 使用代理连接
2026-02-17 13:06:23 +08:00
conn, err = mmInfo.Dialer.Dial("tcp4", serverAddr)
if err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect with proxy attempt %d/%d failed: %s", i+1, maxRetries, err.Error()))
// 检查是否允许降级到直连
if mmInfo.AllowDirectOnProxyFail {
baseutils.PrintLog("MMLongConnect: Proxy failed, falling back to direct connection")
proxyFailed = true // 标记代理失败,后续使用直连
// 不等待,立即尝试直连
} else {
// 不允许直连,等待后重试代理
time.Sleep(retryInterval)
}
continue
}
// 设置连接超时
if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect SetDeadline failed: %s", err.Error()))
conn.Close()
time.Sleep(retryInterval)
2026-02-17 13:06:23 +08:00
continue
}
mmInfo.Conn = conn
mmInfo.reader = bufio.NewReader(conn)
fmt.Println("MMLongConnect with proxy success!")
2026-02-17 13:06:23 +08:00
return nil
}
// 没有使用代理或代理已失败 - 直连
conn, err = net.DialTimeout("tcp4", serverAddr, connTimeout)
2026-02-17 13:06:23 +08:00
if err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect direct attempt %d/%d failed: %s", i+1, maxRetries, err.Error()))
// 等待重试
time.Sleep(retryInterval)
continue
}
// 设置连接超时
if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
baseutils.PrintLog(fmt.Sprintf("MMLongConnect SetDeadline failed: %s", err.Error()))
conn.Close()
time.Sleep(retryInterval)
2026-02-17 13:06:23 +08:00
continue
}
mmInfo.Conn = conn
mmInfo.reader = bufio.NewReader(conn)
if proxyFailed {
fmt.Println("MMLongConnect direct success (after proxy fallback)!")
} else {
fmt.Println("MMLongConnect direct success!")
}
2026-02-17 13:06:23 +08:00
return nil
}
if err != nil {
return fmt.Errorf("MMLongConnect failed after %d attempts: %w", maxRetries, err)
2026-02-17 13:06:23 +08:00
}
return errors.New("MMLongConnect failed: unknown error")
2026-02-17 13:06:23 +08:00
}
// MMTCPSendData MMTCPSendData 长链接发送数据
func MMTCPSendData(mmInfo *MMInfo, data []byte) error {
// 连接服务器
if mmInfo.Conn == nil {
// 提前设置好长链接Host Port
err := MMLongConnect(mmInfo)
if err != nil {
return err
}
}
// 设置写超时
writeTimeout := time.Duration(mmInfo.LongConnTimeout) * time.Second
if writeTimeout <= 0 {
writeTimeout = 15 * time.Second
}
if err := mmInfo.Conn.SetWriteDeadline(time.Now().Add(writeTimeout)); err != nil {
return fmt.Errorf("SetWriteDeadline failed: %w", err)
}
2026-02-17 13:06:23 +08:00
// 发送数据
length, err := mmInfo.Conn.Write(data)
// 判断是否出错
if err != nil {
return fmt.Errorf("write failed: %w", err)
2026-02-17 13:06:23 +08:00
}
// 判断数据是否发送完毕
if length != len(data) {
return errors.New("MMTCPSendData err: length != len(data)")
}
return nil
}
// MMTCPRecvItems 循环接收长链接数据
// Deprecated
func MMTCPRecvItems(mmInfo *MMInfo) ([]*PackItem, error) {
// 设置读超时
readTimeout := time.Duration(mmInfo.LongConnReadTimeout) * time.Second
if readTimeout <= 0 {
readTimeout = time.Duration(mmInfo.LongConnTimeout) * time.Second
if readTimeout <= 0 {
readTimeout = 15 * time.Second
}
}
if err := mmInfo.Conn.SetReadDeadline(time.Now().Add(readTimeout)); err != nil {
return nil, fmt.Errorf("SetReadDeadline failed: %w", err)
}
2026-02-17 13:06:23 +08:00
// 接收返回数据
recvBuf := make([]byte, 10240)
recvLen, err := mmInfo.Conn.Read(recvBuf)
if err != nil {
return nil, err
}
retData := recvBuf[0:recvLen]
retItems, err := ParserMMtlsResponseData(retData)
if err != nil {
return nil, err
}
return retItems, nil
}
// MMTCPRecvOneItem
func MMTCPRecvOneItem(mmInfo *MMInfo) (*PackItem, error) {
if mmInfo == nil || mmInfo.Conn == nil || mmInfo.reader == nil {
return nil, errors.New("mmInfo.Conn or mmInfo.reader is nil")
}
// 设置读超时
readTimeout := time.Duration(mmInfo.LongConnReadTimeout) * time.Second
if readTimeout <= 0 {
readTimeout = time.Duration(mmInfo.LongConnTimeout) * time.Second
if readTimeout <= 0 {
readTimeout = 15 * time.Second
}
}
if err := mmInfo.Conn.SetReadDeadline(time.Now().Add(readTimeout)); err != nil {
return nil, fmt.Errorf("SetReadDeadline failed: %w", err)
}
2026-02-17 13:06:23 +08:00
// 读取头部数据
recordHeadData := make([]byte, 5)
if _, err := io.ReadFull(mmInfo.reader, recordHeadData); err != nil {
return nil, fmt.Errorf("read header failed: %w", err)
2026-02-17 13:06:23 +08:00
}
// 读取Content
recordHead := RecordHeadDeSerialize(recordHeadData)
bodyData := make([]byte, recordHead.Size)
// 重新设置读超时针对body
if err := mmInfo.Conn.SetReadDeadline(time.Now().Add(readTimeout)); err != nil {
return nil, fmt.Errorf("SetReadDeadline for body failed: %w", err)
}
2026-02-17 13:06:23 +08:00
if _, err := io.ReadFull(mmInfo.reader, bodyData); err != nil {
return nil, fmt.Errorf("read body failed: %w", err)
2026-02-17 13:06:23 +08:00
}
return &PackItem{
RecordHead: recordHeadData,
PackData: bodyData,
}, nil
}
// MMTCPSendReq 长链接发送请求
func MMTCPSendReq(mmInfo *MMInfo, opCode uint32, data []byte) error {
sendData, err := MMLongPackData(mmInfo, opCode, data)
if err != nil {
return err
}
// 发送数据
err = MMTCPSendData(mmInfo, sendData)
if err != nil {
return err
}
return nil
}
// MMTCPRecvData 接受MMTLS信息
func MMTCPRecvData(mmInfo *MMInfo) (*LongRecvInfo, error) {
// 接收响应数据
recvItem, err := MMTCPRecvOneItem(mmInfo)
if err != nil {
fmt.Println("MMTCPRecvData err", err.Error())
// log.("接收mmtls长链接响应失败", err.Error())
return nil, err
}
// 解包响应数据
recvInfo, err := MMLongUnPackData(mmInfo, recvItem)
if err != nil {
fmt.Println("MMTCPRecvData err", err.Error())
//log.Info("解包响应数据失败", err.Error())
return nil, err
}
return recvInfo, nil
}