|
@@ -0,0 +1,225 @@
|
|
|
|
+package config
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "cicv-data-closedloop/common/config/c_log"
|
|
|
|
+ "encoding/json"
|
|
|
|
+ "fmt"
|
|
|
|
+ "github.com/gorilla/websocket"
|
|
|
|
+ "net/url"
|
|
|
|
+ "time"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+var (
|
|
|
|
+ WsConn *websocket.Conn
|
|
|
|
+ reconnectionInProgress bool
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// Request 结构体定义
|
|
|
|
+type Request struct {
|
|
|
|
+ Type string `json:"type"`
|
|
|
|
+ UUID string `json:"uuid"`
|
|
|
|
+ CommandID string `json:"commandId"`
|
|
|
|
+ Parameter interface{} `json:"parameter"`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Request1 结构体定义
|
|
|
|
+type Request1 struct {
|
|
|
|
+ Type string `json:"type"`
|
|
|
|
+ CommandID string `json:"commandId"`
|
|
|
|
+ Parameter interface{} `json:"parameter"`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Response 结构体定义
|
|
|
|
+type Response struct {
|
|
|
|
+ CommandID string `json:"commandId"`
|
|
|
|
+ ErrorCode string `json:"errorCode"`
|
|
|
|
+ Results map[string]string `json:"results"`
|
|
|
|
+ Status string `json:"status"`
|
|
|
|
+ Time int64 `json:"time"`
|
|
|
|
+ Type string `json:"type"`
|
|
|
|
+ UUID string `json:"uuid"`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// StatusMessage 状态消息 结构体定义
|
|
|
|
+type StatusMessage struct {
|
|
|
|
+ Type string `json:"type"`
|
|
|
|
+ Topic string `json:"topic"`
|
|
|
|
+ Time int64 `json:"time"`
|
|
|
|
+ Data interface{} `json:"data"`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func keepAlive() {
|
|
|
|
+ ticker := time.NewTicker(30 * time.Second)
|
|
|
|
+ defer ticker.Stop()
|
|
|
|
+
|
|
|
|
+ request := Request1{
|
|
|
|
+ Type: "request",
|
|
|
|
+ CommandID: "heart",
|
|
|
|
+ Parameter: nil,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requestJSON, err := json.Marshal(request)
|
|
|
|
+ if err != nil {
|
|
|
|
+ //c_log.GlobalLogger.Error("保持websocket连接活跃,解析requestJSON - 失败。", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case <-ticker.C:
|
|
|
|
+ err := WsConn.WriteMessage(websocket.TextMessage, requestJSON)
|
|
|
|
+ if err != nil {
|
|
|
|
+ //c_log.GlobalLogger.Error("保持websocket连接活跃,发送心跳请求 - 失败。", err)
|
|
|
|
+ WsConn.Close()
|
|
|
|
+ //c_log.GlobalLogger.Info("重试连接websocket...")
|
|
|
|
+ ConnectWebsocket() // 重新连接
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ //c_log.GlobalLogger.Info("保持websocket连接活跃,发送心跳请求 - 成功。")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func SendWebsocketHeartbeat(conn *websocket.Conn, maxRetries int) (bool, error) {
|
|
|
|
+
|
|
|
|
+ request := Request1{
|
|
|
|
+ Type: "request",
|
|
|
|
+ CommandID: "heart",
|
|
|
|
+ Parameter: nil,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 将请求JSON编码为字节
|
|
|
|
+ requestJSON, err := json.Marshal(request)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return false, fmt.Errorf("marshal request: %w", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 发送WebSocket消息
|
|
|
|
+ err = conn.WriteMessage(websocket.TextMessage, requestJSON)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return false, fmt.Errorf("write: %w", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ count := 0
|
|
|
|
+ for {
|
|
|
|
+ if count > maxRetries {
|
|
|
|
+ return false, fmt.Errorf("保持websocket连接活跃,读取websocket消息超过最大重试次数。")
|
|
|
|
+ }
|
|
|
|
+ time.Sleep(1 * time.Second)
|
|
|
|
+ _, message, err := conn.ReadMessage()
|
|
|
|
+ if err != nil {
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,读取websocket消息 - 失败 ", err, " 继续读取消息。")
|
|
|
|
+ return false, err
|
|
|
|
+ //continue
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var response Response
|
|
|
|
+ err = json.Unmarshal(message, &response)
|
|
|
|
+ c_log.GlobalLogger.Info("response ", response)
|
|
|
|
+ if err == nil && response.Type == "response" {
|
|
|
|
+ c_log.GlobalLogger.Info("response1 ", response)
|
|
|
|
+ return true, err
|
|
|
|
+ }
|
|
|
|
+ count++
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func sendRequestAndAwaitResponse(ws *websocket.Conn) ([]byte, error) {
|
|
|
|
+ request := Request1{
|
|
|
|
+ Type: "request",
|
|
|
|
+ CommandID: "heart",
|
|
|
|
+ Parameter: nil,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requestJSON, err := json.Marshal(request)
|
|
|
|
+ if err != nil {
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,解析requestJSON - 失败。", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = ws.WriteMessage(websocket.TextMessage, requestJSON)
|
|
|
|
+ if err != nil {
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,发送心跳请求 - 失败。", err)
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ c_log.GlobalLogger.Info("保持websocket连接活跃,发送心跳请求 - 成功。")
|
|
|
|
+
|
|
|
|
+ // 使用channel等待响应
|
|
|
|
+ responseChan := make(chan []byte)
|
|
|
|
+ go handleMessages(ws, responseChan)
|
|
|
|
+
|
|
|
|
+ select {
|
|
|
|
+ case response := <-responseChan:
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,等待心跳响应 - 成功。")
|
|
|
|
+ return response, nil
|
|
|
|
+ case <-time.After(60 * time.Second): // 设置超时时间
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,等待心跳响应 - 超时。")
|
|
|
|
+ close(responseChan)
|
|
|
|
+ return nil, fmt.Errorf("保持websocket连接活跃,等待心跳响应 - 超时。")
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func handleMessages(ws *websocket.Conn, responseChan chan<- []byte) {
|
|
|
|
+ for {
|
|
|
|
+ time.Sleep(100 * time.Millisecond)
|
|
|
|
+ _, message, err := ws.ReadMessage()
|
|
|
|
+ if err != nil {
|
|
|
|
+ c_log.GlobalLogger.Error("保持websocket连接活跃,读取websocket消息 - 失败 ", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var response Response
|
|
|
|
+ if err := json.Unmarshal(message, &response); err == nil && response.Type == "response" {
|
|
|
|
+ responseChan <- message
|
|
|
|
+ close(responseChan)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func ConnectWebsocket() {
|
|
|
|
+ for {
|
|
|
|
+ // 防止重复调用
|
|
|
|
+ if reconnectionInProgress {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ reconnectionInProgress = true
|
|
|
|
+ //c_log.GlobalLogger.Info("初始化Websocket连接 - 开始。")
|
|
|
|
+ serverURL := LocalConfig.Node.Ip + ":" + LocalConfig.LocalWebsocketPort
|
|
|
|
+ path := "/"
|
|
|
|
+
|
|
|
|
+ // 构建WebSocket连接URL
|
|
|
|
+ u := url.URL{Scheme: "ws", Host: serverURL, Path: path}
|
|
|
|
+ //c_log.GlobalLogger.Info("URL:", u.String())
|
|
|
|
+
|
|
|
|
+ // 创建一个Dialer实例,用于建立WebSocket连接
|
|
|
|
+ dialer := websocket.Dialer{
|
|
|
|
+ ReadBufferSize: 1024,
|
|
|
|
+ WriteBufferSize: 1024,
|
|
|
|
+ // 可选:设置超时等
|
|
|
|
+ HandshakeTimeout: 5 * time.Minute,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 建立WebSocket连接
|
|
|
|
+ coon, _, err := dialer.Dial(u.String(), nil)
|
|
|
|
+ if err != nil {
|
|
|
|
+ fmt.Println("err:", err)
|
|
|
|
+ //c_log.GlobalLogger.Error("初始化Websocket连接 - 失败。")
|
|
|
|
+ time.Sleep(5 * time.Second)
|
|
|
|
+ reconnectionInProgress = false
|
|
|
|
+ //c_log.GlobalLogger.Info("重试连接websocket...")
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ WsConn = coon
|
|
|
|
+ //c_log.GlobalLogger.Info("初始化Websocket连接 - 成功。")
|
|
|
|
+ // 连接成功,退出循环
|
|
|
|
+ reconnectionInProgress = false
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func InitWebsocketConfig() {
|
|
|
|
+ ConnectWebsocket()
|
|
|
|
+ // 保持连接活跃
|
|
|
|
+ go keepAlive()
|
|
|
|
+}
|