Files
blackbird/gomsg/client.go
T
qing c4154d4db9 feat(gomsg): pymsg/libmsg 协议的 Go 实现,waf logclient 抽取接入
- 新增 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 编译通过
2026-08-23 11:21:40 +00:00

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
}