star-cloud/mqtt-gateway/internal/handler/mqtt_handler.go

112 lines
2.5 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, "/")
// 尋找事件類型 (connected 或 disconnected)
var event string
for _, p := range parts {
if p == "connected" || p == "disconnected" {
event = p
break
}
}
// 尋找 Client ID (通常位於 "clients" 的下一層)
for i, p := range parts {
if p == "clients" && i+1 < len(parts) {
serialNo = parts[i+1]
break
}
}
if event != "" && serialNo != "" {
// 解析系統 JSON Payload (補強:有些版本會把 ClientID 放在 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
}