feat: 新增WebSocket客户端和配置加载器以支持网络通信
This commit is contained in:
parent
b5071eb15b
commit
b19af56f80
|
|
@ -0,0 +1,133 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/wuko233/sysmonitord/internal/config"
|
||||
)
|
||||
|
||||
type ConfigLoader struct {
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewConfigLoader() *ConfigLoader {
|
||||
return &ConfigLoader{
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ConfigLoader) LoadConfigs(urls ConfigUrls) (config.OfficialConfig, config.UserConfig, error) {
|
||||
var official config.OfficialConfig
|
||||
var user config.UserConfig
|
||||
// 1. 下载官方配置
|
||||
if err := l.fetchJSON(urls.OfficialConfigUrl, &official); err != nil {
|
||||
return official, user, fmt.Errorf("下载官方配置失败: %v", err)
|
||||
}
|
||||
// 2. 下载用户配置
|
||||
if err := l.fetchJSON(urls.UserConfigUrl, &user); err != nil {
|
||||
return official, user, fmt.Errorf("下载用户配置失败: %v", err)
|
||||
}
|
||||
return official, user, nil
|
||||
}
|
||||
|
||||
func (l *ConfigLoader) fetchJSON(url string, target interface{}) error {
|
||||
resp, err := l.client.Get(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("非200响应: %d", resp.StatusCode)
|
||||
}
|
||||
return json.NewDecoder(resp.Body).Decode(target)
|
||||
}
|
||||
|
|
@ -15,3 +15,8 @@ func NewPactet(msgType string, payload interface{}) Packet {
|
|||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
type ConfigUrls struct {
|
||||
OfficialConfigUrl string
|
||||
UserConfigUrl string
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user