star-cloud/mqtt-gateway/internal/handler/mqtt_handler.go
sky121113 32bc13ac1b [FIX] 修復 MQTT 監聽器與機台連線狀態同步邏輯
1. 補齊 ListenMqttQueue 中的 Job 類別引用,修復 mqtt-worker 崩潰重啟問題。
2. 實作 Go Gateway 的 Client ID 解析邏輯,正確將 SC_{serial}_{random} 格式還原為機台編號。
3. 修復  系統主題解析與 Laravel ProcessStatus Job 對齊,實現毫秒級連線狀態同步。
4. 在 ProcessStatus Job 中增加第二層 serial_no 清理保險,提高系統容錯。
5. 更新機台列表 UI 狀態顯示邏輯,支援 在線/斷線/故障 三態顯示與多語系。
6. 更新 MQTT 通訊規範 (Skill) 文件,確保全域開發定義的一致性。
7. 同步更新 zh_TW.json, en.json, ja.json 翻譯文件。
2026-04-21 12:38:42 +08:00

97 lines
2.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"encoding/json"
"log"
"star-cloud-gateway/internal/bridge"
"strings"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
type MqttHandler struct {
pusher *bridge.RedisPusher
}
func NewMqttHandler(pusher *bridge.RedisPusher) *MqttHandler {
return &MqttHandler{pusher: pusher}
}
func (h *MqttHandler) HandleMessage(client mqtt.Client, msg mqtt.Message) {
topic := msg.Topic()
payload := msg.Payload()
log.Printf("Received message on topic: %s", topic)
var serialNo, msgType string
var jsonPayload interface{}
// 檢查是否為系統主題 ($SYS)
if strings.HasPrefix(topic, "$SYS/") {
parts := strings.Split(topic, "/")
if len(parts) >= 6 {
serialNo = parts[4]
event := parts[5]
// 解析系統 JSON Payload
var sysData map[string]interface{}
if err := json.Unmarshal(payload, &sysData); err == nil {
if cid, ok := sysData["clientid"].(string); ok {
serialNo = cid
}
}
msgType = "status"
statusValue := "online"
if event == "disconnected" {
statusValue = "offline"
}
jsonPayload = map[string]string{"status": statusValue}
log.Printf("Detected system event: Client [%s] is now [%s]", serialNo, statusValue)
} else {
return
}
} else {
// 一般業務主題 (machine/{serialNo}/{type})
parts := strings.Split(topic, "/")
if len(parts) < 3 {
return
}
serialNo = parts[1]
msgType = parts[2]
err := json.Unmarshal(payload, &jsonPayload)
if err != nil {
// 如果不是有效的 JSON則視為純文字/數值 (Raw Value)
jsonPayload = string(payload)
}
}
bridgePayload := bridge.BridgePayload{
Type: msgType,
SerialNo: cleanSerialNo(serialNo),
Payload: jsonPayload,
}
h.pusher.Push(bridgePayload)
}
// cleanSerialNo 處理 Client ID 格式,將 SC_M0408_pndk 轉為 M0408
func cleanSerialNo(clientID string) string {
if clientID == "" {
return ""
}
// 1. 移除已知前綴 SC_
cleaned := strings.TrimPrefix(clientID, "SC_")
// 2. 如果中間還有底線,通常代表隨機碼,只取前面部分
// 例如 M0408_test -> M0408
if idx := strings.Index(cleaned, "_"); idx != -1 {
return cleaned[:idx]
}
return cleaned
}