- 新增 gomsg/:帧协议(4B 大端长度 + UTF-8,64MiB 上限)、MsgClient/MsgServer、 RpcClient/RpcServer(_route 分发、错误脱敏、panic 恢复、json.Number 保精度)、 AsyncQueue[T]、LogClient(集中式日志,级别过滤 + fail-safe),线协议与 Python/C++ 字节级兼容 - waf/internal/logclient 改为 gomsg 薄适配层(336→20 行),main/engine/proxy 零改动 - gomsg 26 项单测全绿(-race);waf 编译通过
107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package gomsg
|
|
|
|
import (
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// DefaultTimeout 单次请求-响应交互的总超时。
|
|
const DefaultTimeout = 5 * time.Second
|
|
|
|
// MsgClient pymsg 协议客户端:复用长连接 + 请求-响应调用。
|
|
// 连接断开时自动重建一次(对应 Python pymsg.MsgClient / C++ libmsg.MsgClient)。
|
|
type MsgClient struct {
|
|
addr string
|
|
timeout time.Duration
|
|
|
|
mu sync.Mutex
|
|
conn net.Conn
|
|
}
|
|
|
|
// NewMsgClient 创建客户端。timeout 为 0 时使用 DefaultTimeout。
|
|
func NewMsgClient(addr string, timeout time.Duration) *MsgClient {
|
|
if timeout <= 0 {
|
|
timeout = DefaultTimeout
|
|
}
|
|
return &MsgClient{addr: addr, timeout: timeout}
|
|
}
|
|
|
|
// Call 发送一条请求并读取响应(复用长连接,失败时关闭重连一次)。
|
|
// 返回响应载荷;超时 / 连接错误返回 error。
|
|
func (c *MsgClient) Call(payload []byte) ([]byte, error) {
|
|
resp, err := c.call(payload)
|
|
if err == nil {
|
|
return resp, nil
|
|
}
|
|
// 旧连接可能已断开(服务端重启等),关闭后重连一次
|
|
c.closeConn()
|
|
return c.call(payload)
|
|
}
|
|
|
|
// Send 发送一条请求,不等待响应(fire-and-forget)。失败时重连一次。
|
|
func (c *MsgClient) Send(payload []byte) error {
|
|
if err := c.sendOnly(payload); err != nil {
|
|
c.closeConn()
|
|
return c.sendOnly(payload)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Close 关闭底层连接。
|
|
func (c *MsgClient) Close() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
return c.closeLocked()
|
|
}
|
|
|
|
func (c *MsgClient) call(payload []byte) ([]byte, error) {
|
|
conn, err := c.getConn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_ = conn.SetDeadline(time.Now().Add(c.timeout))
|
|
if err := WriteFrame(conn, payload); err != nil {
|
|
return nil, err
|
|
}
|
|
return ReadFrame(conn, 0)
|
|
}
|
|
|
|
func (c *MsgClient) sendOnly(payload []byte) error {
|
|
conn, err := c.getConn()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = conn.SetWriteDeadline(time.Now().Add(c.timeout))
|
|
return WriteFrame(conn, payload)
|
|
}
|
|
|
|
func (c *MsgClient) getConn() (net.Conn, error) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if c.conn != nil {
|
|
return c.conn, nil
|
|
}
|
|
conn, err := net.DialTimeout("tcp", c.addr, c.timeout)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
c.conn = conn
|
|
return conn, nil
|
|
}
|
|
|
|
func (c *MsgClient) closeConn() {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
_ = c.closeLocked()
|
|
}
|
|
|
|
func (c *MsgClient) closeLocked() error {
|
|
if c.conn != nil {
|
|
err := c.conn.Close()
|
|
c.conn = nil
|
|
return err
|
|
}
|
|
return nil
|
|
}
|