增加websocket支持
This commit is contained in:
174
internal/core/websocket.go
Normal file
174
internal/core/websocket.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Package core 提供WebSocket服务功能
|
||||
// 实现中继设备和平台之间的双向通信
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/logs"
|
||||
"git.huangwc.com/pig/pig-farm-controller/internal/model"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// WebSocket消息类型常量
|
||||
const (
|
||||
// MessageTypeCommand 平台向设备发送的指令
|
||||
MessageTypeCommand = "command"
|
||||
|
||||
// MessageTypeResponse 设备向平台发送的响应
|
||||
MessageTypeResponse = "response"
|
||||
|
||||
// MessageTypeHeartbeat 心跳消息
|
||||
MessageTypeHeartbeat = "heartbeat"
|
||||
)
|
||||
|
||||
// WebSocketMessage WebSocket消息结构
|
||||
type WebSocketMessage struct {
|
||||
// Type 消息类型
|
||||
Type string `json:"type"`
|
||||
|
||||
// DeviceID 设备ID
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
|
||||
// Command 指令内容
|
||||
Command string `json:"command,omitempty"`
|
||||
|
||||
// Data 消息数据
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
|
||||
// Timestamp 时间戳
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// DeviceConnection 设备连接信息
|
||||
type DeviceConnection struct {
|
||||
// DeviceID 设备ID
|
||||
DeviceID string
|
||||
|
||||
// Connection WebSocket连接
|
||||
Connection *websocket.Conn
|
||||
|
||||
// LastHeartbeat 最后心跳时间
|
||||
LastHeartbeat time.Time
|
||||
|
||||
// DeviceInfo 设备信息
|
||||
DeviceInfo *model.Device
|
||||
}
|
||||
|
||||
// WebSocketService WebSocket服务
|
||||
type WebSocketService struct {
|
||||
// connections 设备连接映射
|
||||
connections map[string]*DeviceConnection
|
||||
|
||||
// mutex 互斥锁
|
||||
mutex sync.RWMutex
|
||||
|
||||
// logger 日志记录器
|
||||
logger *logs.Logger
|
||||
}
|
||||
|
||||
// NewWebSocketService 创建WebSocket服务实例
|
||||
func NewWebSocketService() *WebSocketService {
|
||||
return &WebSocketService{
|
||||
connections: make(map[string]*DeviceConnection),
|
||||
logger: logs.NewLogger(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddConnection 添加设备连接
|
||||
func (ws *WebSocketService) AddConnection(deviceID string, conn *websocket.Conn) {
|
||||
ws.mutex.Lock()
|
||||
defer ws.mutex.Unlock()
|
||||
|
||||
ws.connections[deviceID] = &DeviceConnection{
|
||||
DeviceID: deviceID,
|
||||
Connection: conn,
|
||||
LastHeartbeat: time.Now(),
|
||||
}
|
||||
|
||||
ws.logger.Info(fmt.Sprintf("设备 %s 已连接", deviceID))
|
||||
}
|
||||
|
||||
// RemoveConnection 移除设备连接
|
||||
func (ws *WebSocketService) RemoveConnection(deviceID string) {
|
||||
ws.mutex.Lock()
|
||||
defer ws.mutex.Unlock()
|
||||
|
||||
delete(ws.connections, deviceID)
|
||||
|
||||
ws.logger.Info(fmt.Sprintf("设备 %s 已断开连接", deviceID))
|
||||
}
|
||||
|
||||
// SendCommand 向指定设备发送指令
|
||||
func (ws *WebSocketService) SendCommand(deviceID, command string, data interface{}) error {
|
||||
ws.mutex.RLock()
|
||||
deviceConn, exists := ws.connections[deviceID]
|
||||
ws.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return fmt.Errorf("设备 %s 未连接", deviceID)
|
||||
}
|
||||
|
||||
// 构造消息
|
||||
msg := WebSocketMessage{
|
||||
Type: MessageTypeCommand,
|
||||
Command: command,
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
if err := deviceConn.Connection.WriteJSON(msg); err != nil {
|
||||
return fmt.Errorf("向设备 %s 发送指令失败: %v", deviceID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConnectedDevices 获取已连接的设备列表
|
||||
func (ws *WebSocketService) GetConnectedDevices() []string {
|
||||
ws.mutex.RLock()
|
||||
defer ws.mutex.RUnlock()
|
||||
|
||||
devices := make([]string, 0, len(ws.connections))
|
||||
for deviceID := range ws.connections {
|
||||
devices = append(devices, deviceID)
|
||||
}
|
||||
|
||||
return devices
|
||||
}
|
||||
|
||||
// HandleMessage 处理来自设备的消息
|
||||
func (ws *WebSocketService) HandleMessage(deviceID string, message []byte) error {
|
||||
// 解析消息
|
||||
var msg WebSocketMessage
|
||||
if err := json.Unmarshal(message, &msg); err != nil {
|
||||
return fmt.Errorf("解析设备 %s 消息失败: %v", deviceID, err)
|
||||
}
|
||||
|
||||
// 更新心跳时间
|
||||
if msg.Type == MessageTypeHeartbeat {
|
||||
ws.mutex.Lock()
|
||||
if deviceConn, exists := ws.connections[deviceID]; exists {
|
||||
deviceConn.LastHeartbeat = time.Now()
|
||||
}
|
||||
ws.mutex.Unlock()
|
||||
}
|
||||
|
||||
// 记录消息日志
|
||||
ws.logger.Info(fmt.Sprintf("收到来自设备 %s 的消息: %v", deviceID, msg))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDeviceConnection 获取设备连接信息
|
||||
func (ws *WebSocketService) GetDeviceConnection(deviceID string) (*DeviceConnection, bool) {
|
||||
ws.mutex.RLock()
|
||||
defer ws.mutex.RUnlock()
|
||||
|
||||
deviceConn, exists := ws.connections[deviceID]
|
||||
return deviceConn, exists
|
||||
}
|
||||
Reference in New Issue
Block a user