Files
wechat_ipad_pro/clientsdk/mmtls/mmlonglinknet.go

250 lines
6.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
// }
// 打印 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)
// 定义
var conn net.Conn
var err error
proxyFailed := false // 标记代理是否已经失败过
for i := 0; i < maxRetries; i++ {
// 如果有代理且代理没有被标记为失败,尝试代理连接
if mmInfo.Dialer != nil && !proxyFailed {
// 使用代理连接
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)
continue
}
mmInfo.Conn = conn
mmInfo.reader = bufio.NewReader(conn)
fmt.Println("MMLongConnect with proxy success!")
return nil
}
// 没有使用代理或代理已失败 - 直连
conn, err = net.DialTimeout("tcp4", serverAddr, connTimeout)
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)
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!")
}
return nil
}
if err != nil {
return fmt.Errorf("MMLongConnect failed after %d attempts: %w", maxRetries, err)
}
return errors.New("MMLongConnect failed: unknown error")
}
// 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)
}
// 发送数据
length, err := mmInfo.Conn.Write(data)
// 判断是否出错
if err != nil {
return fmt.Errorf("write failed: %w", err)
}
// 判断数据是否发送完毕
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)
}
// 接收返回数据
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)
}
// 读取头部数据
recordHeadData := make([]byte, 5)
if _, err := io.ReadFull(mmInfo.reader, recordHeadData); err != nil {
return nil, fmt.Errorf("read header failed: %w", err)
}
// 读取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)
}
if _, err := io.ReadFull(mmInfo.reader, bodyData); err != nil {
return nil, fmt.Errorf("read body failed: %w", err)
}
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
}