package camera import ( "bufio" "bytes" "context" "fmt" "net" "sync" "time" "github.com/zeromicro/go-zero/core/logx" ) // 命令常量 const ( CmdTakePhoto = "T1" CmdGetDetectionResult = "GM,2,0" ) type Client struct { addr string conn net.Conn timeout time.Duration mu sync.Mutex } func NewClient(addr string, timeout ...time.Duration) *Client { t := 1 * time.Second if len(timeout) > 0 { t = timeout[0] } return &Client{ addr: addr, timeout: t, } } func (c *Client) Connect() error { logx.Infof("正在连接相机: %s", c.addr) conn, err := net.DialTimeout("tcp", c.addr, c.timeout) if err != nil { logx.Errorf("相机连接失败: %v", err) return fmt.Errorf("相机连接失败: %w", err) } c.conn = conn logx.Infof("相机连接成功: %s", c.addr) return nil } func (c *Client) ConnectWithRetry(maxRetries int, retryInterval time.Duration) error { var err error for i := 0; i < maxRetries; i++ { err = c.Connect() if err == nil { return nil } logx.Errorf("连接失败,%v后重试...", retryInterval) time.Sleep(retryInterval) } return fmt.Errorf("连接相机失败: %w", err) } func (c *Client) IsConnected() bool { return c.conn != nil } func (c *Client) Reconnect() error { c.Close() return c.Connect() } func (c *Client) SendCommand(cmd string) ([]byte, error) { c.mu.Lock() defer c.mu.Unlock() if c.conn == nil { return nil, fmt.Errorf("未建立连接") } logx.Infof("发送相机指令: %s", cmd) _, err := c.conn.Write([]byte(cmd + "\r")) if err != nil { logx.Errorf("发送指令失败: %v", err) return nil, fmt.Errorf("发送指令失败: %w", err) } resp, err := c.readResponse() if err != nil { return nil, err } logx.Infof("收到相机响应: %s", string(resp)) return resp, nil } func (c *Client) readResponse() ([]byte, error) { reader := bufio.NewReader(c.conn) var buffer bytes.Buffer if err := c.conn.SetReadDeadline(time.Now().Add(c.timeout)); err != nil { return nil, err } for { b, err := reader.ReadByte() if err != nil { return nil, err } buffer.WriteByte(b) if b == '\r' || b == '\n' { break } } return buffer.Bytes(), nil } func (c *Client) SendCommandWithContext(ctx context.Context, cmd string) ([]byte, error) { type result struct { resp []byte err error } ch := make(chan result, 1) go func() { resp, err := c.SendCommand(cmd) ch <- result{resp, err} }() select { case <-ctx.Done(): return nil, ctx.Err() case res := <-ch: return res.resp, res.err } } func (c *Client) TakePhoto() error { _, err := c.SendCommand(CmdTakePhoto) return err } func (c *Client) GetDetectionResult() (string, error) { resp, err := c.SendCommand(CmdGetDetectionResult) if err != nil { return "", err } return string(resp), nil } func (c *Client) Close() { if c.conn != nil { c.conn.Close() c.conn = nil logx.Infof("相机连接已关闭") } }