142 lines
2.5 KiB
Go
142 lines
2.5 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() error {
|
|
conn, _, err := websocket.DefaultDialer.Dial(c.config.ServerURL, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
select {
|
|
case <-c.stopChan:
|
|
conn.Close()
|
|
return nil
|
|
default:
|
|
}
|
|
|
|
c.conn = conn
|
|
c.isConnected = true
|
|
log.Printf("[网络] 成功连接到服务器: %s", c.config.ServerURL)
|
|
return nil
|
|
}
|