sysmonitord/internal/network/client.go

134 lines
2.4 KiB
Go

package network
import (
"encoding/json"
"log"
"sync"
"time"
"github.com/gorilla/websocket"
)
type ClientConfig struct {
ServerURL string
SendInterval time.Duration
BufferSize int
}
type WSClient struct {
config ClientConfig
conn *websocket.Conn
sendChan chan Packet
mu sync.Mutex
isConnected bool
stopChan chan struct{}
}
func NewWSClient(cfg ClientConfig) *WSClient {
if cfg.BufferSize == 0 {
cfg.BufferSize = 100
}
return &WSClient{
config: cfg,
sendChan: make(chan Packet, cfg.BufferSize),
stopChan: make(chan struct{}),
}
}
func (c *WSClient) Start() {
go c.connectionLoop()
go c.sendLoop()
}
func (c *WSClient) SendQueue(packet Packet) {
select {
case c.sendChan <- packet:
default:
log.Printf("[网络] 发送队列已满,丢弃消息: %s", packet.Type)
}
}
func (c *WSClient) Stop() {
close(c.stopChan)
if c.conn != nil {
c.conn.Close()
}
}
func (c *WSClient) sendLoop() {
for {
select {
case <-c.stopChan:
return
case packet := <-c.sendChan:
c.sendRaw(packet)
}
}
}
func (c *WSClient) sendRaw(packet Packet) {
c.mu.Lock()
defer c.mu.Unlock()
if !c.isConnected || c.conn == nil {
log.Printf("[网络] 无连接,无法发送消息: %s", packet.Type)
return
}
c.conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
payload, _ := json.Marshal(packet)
if err := c.conn.WriteMessage(websocket.TextMessage, payload); err != nil {
log.Printf("[网络] 发送消息失败: %v", err)
c.isConnected = false
}
}
func (c *WSClient) connectionLoop() {
for {
select {
case <-c.stopChan:
return
default:
if !c.isConnected {
if err := c.connect(); err != nil {
log.Printf("[网络] 连接 %s 失败: %v. 5秒后重试...", c.config.ServerURL, err)
time.Sleep(5 * time.Second)
continue
}
}
_, _, err := c.conn.ReadMessage()
if err != nil {
log.Printf("[网络] 连接断开: %v", err)
c.closeConn()
}
// TODO: 处理服务器消息
}
}
}
func (c *WSClient) closeConn() {
c.mu.Lock()
defer c.mu.Unlock()
if c.conn != nil {
c.conn.Close()
c.conn = nil
}
c.isConnected = false
}
func (c *WSClient) connect() any {
c.mu.Lock()
defer c.mu.Unlock()
conn, _, err := websocket.DefaultDialer.Dial(c.config.ServerURL, nil)
if err != nil {
return err
}
c.conn = conn
c.isConnected = true
log.Printf("[网络] 成功连接到服务器: %s", c.config.ServerURL)
return nil
}