2023-11-16 16:54:23 +08:00
|
|
|
package mqtt
|
|
|
|
|
|
|
|
import (
|
2023-12-20 10:37:54 +08:00
|
|
|
"context"
|
2023-11-17 14:12:37 +08:00
|
|
|
"fmt"
|
2023-11-16 16:54:23 +08:00
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
"github.com/eclipse/paho.golang/autopaho"
|
|
|
|
"github.com/eclipse/paho.golang/paho"
|
|
|
|
"github.com/sagikazarmark/slog-shim"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
2024-01-11 10:24:56 +08:00
|
|
|
"joylink.club/bj-rtsts-server/dto/state_proto"
|
2023-11-16 16:54:23 +08:00
|
|
|
)
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
var mqttClient *MqttClient
|
2023-11-16 16:54:23 +08:00
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 客户端
|
|
|
|
type MqttClient struct {
|
2024-01-23 09:37:31 +08:00
|
|
|
cc *autopaho.ClientConfig
|
|
|
|
cm *autopaho.ConnectionManager
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 初始化并启动MQTT客户端服务
|
|
|
|
func Startup(cmc *MqttOptions) error {
|
|
|
|
if err := checkConfig(cmc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cc, err := cmc.tryInto()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-05-07 10:52:29 +08:00
|
|
|
ctx := context.Background()
|
|
|
|
cm, err := autopaho.NewConnection(ctx, *cc)
|
2023-12-20 10:37:54 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-05-07 10:52:29 +08:00
|
|
|
//添加等待连接,如果连接失败,则等待重连
|
|
|
|
if err = cm.AwaitConnection(ctx); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2024-01-23 09:37:31 +08:00
|
|
|
mqttClient = &MqttClient{cc: cc, cm: cm}
|
2023-12-20 10:37:54 +08:00
|
|
|
return nil
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 检查配置信息
|
|
|
|
func checkConfig(cmc *MqttOptions) error {
|
|
|
|
if cmc.AppId == "" {
|
|
|
|
return fmt.Errorf("应用编号不能为空")
|
|
|
|
}
|
|
|
|
if cmc.ClientId == "" {
|
|
|
|
return fmt.Errorf("客户端编号不能为空")
|
|
|
|
}
|
|
|
|
if cmc.BrokerUrl == "" {
|
|
|
|
return fmt.Errorf("MQTT代理服务地址不能为空")
|
|
|
|
}
|
|
|
|
if cmc.Username == "" {
|
|
|
|
return fmt.Errorf("MQTT用户名不能为空")
|
|
|
|
}
|
|
|
|
if cmc.Password == "" {
|
|
|
|
return fmt.Errorf("MQTT密码不能为空")
|
|
|
|
}
|
|
|
|
return nil
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
|
|
|
|
2023-12-25 14:15:22 +08:00
|
|
|
func GetMsgClient() *MqttClient {
|
|
|
|
return mqttClient
|
2023-11-17 14:12:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 获取MQTT客户端id
|
|
|
|
func GetClientId() string {
|
2023-12-25 14:15:22 +08:00
|
|
|
return mqttClient.cc.ClientConfig.ClientID
|
2023-11-17 14:12:37 +08:00
|
|
|
}
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 发布数据
|
2023-12-25 14:15:22 +08:00
|
|
|
func (client *MqttClient) pub(topic string, data protoreflect.ProtoMessage) error {
|
2023-12-20 10:37:54 +08:00
|
|
|
if data == nil {
|
|
|
|
return fmt.Errorf("发布数据引用为nil")
|
|
|
|
}
|
|
|
|
b, err := proto.Marshal(data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
2023-12-20 10:37:54 +08:00
|
|
|
if !MatchTopic(topic) {
|
|
|
|
slog.Error("未知发布主题", "topic", topic, "data", data)
|
|
|
|
return fmt.Errorf("未知发布主题: topic=%s", topic)
|
|
|
|
}
|
2024-01-23 09:37:31 +08:00
|
|
|
// else {
|
|
|
|
// slog.Debug("发布主题", "topic", topic, "data", data)
|
|
|
|
// }
|
2023-12-25 14:15:22 +08:00
|
|
|
_, err = client.cm.Publish(context.Background(), &paho.Publish{
|
2023-12-20 10:37:54 +08:00
|
|
|
Topic: topic,
|
|
|
|
QoS: 0,
|
|
|
|
Payload: b,
|
|
|
|
})
|
|
|
|
return err
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
|
|
|
|
2024-05-07 10:52:29 +08:00
|
|
|
// 订阅mqtt服务
|
|
|
|
/*func subHandle(p *paho.Publish) {
|
|
|
|
fmt.Println(fmt.Sprintf("%v-%v"), hex.EncodeToString(p.Payload), len(p.Payload))
|
|
|
|
}
|
|
|
|
func (client *MqttClient) SubSimulationState(simulationId string) (*paho.Suback, error) {
|
|
|
|
topIc := GetStateTopic(simulationId)
|
|
|
|
_, err2 := client.cm.Subscribe(context.Background(), &paho.Subscribe{Subscriptions: []paho.SubscribeOptions{{Topic: topIc, QoS: 0}}})
|
|
|
|
if err2 != nil {
|
|
|
|
fmt.Println(err2)
|
|
|
|
}
|
|
|
|
client.cc.Router.RegisterHandler(topIc, subHandle)
|
|
|
|
return nil, nil
|
|
|
|
}*/
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 发送仿真状态数据
|
2024-01-11 10:24:56 +08:00
|
|
|
func (client *MqttClient) PubSimulationState(simulationId string, msg *state_proto.SimulationStatus) error {
|
2023-12-25 14:15:22 +08:00
|
|
|
return client.pub(GetStateTopic(simulationId), msg)
|
2023-12-20 10:37:54 +08:00
|
|
|
}
|
|
|
|
|
2024-01-23 09:37:31 +08:00
|
|
|
func (c *MqttClient) PubTpapiServiceState(simulationId string, msg *state_proto.SimulationThirdPartyApiService) error {
|
|
|
|
return c.pub(GetTpapiServiceTopic(simulationId), msg)
|
|
|
|
}
|
|
|
|
|
2023-12-20 10:37:54 +08:00
|
|
|
// 发送IBP状态数据
|
2024-02-20 14:18:42 +08:00
|
|
|
func (client *MqttClient) PubIBPState(simulationId string, mapId int32, ibpId uint32, msg *state_proto.PushedDevicesStatus) error {
|
|
|
|
return client.pub(GetIbpTopic(simulationId, mapId, ibpId), msg)
|
2023-12-20 10:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 发送PSL状态数据
|
2024-01-11 10:24:56 +08:00
|
|
|
func (client *MqttClient) PubPSLState(simulationId string, mapId int32, boxId uint32, msg *state_proto.PushedDevicesStatus) error {
|
2023-12-25 14:15:22 +08:00
|
|
|
return client.pub(GetPslTopic(simulationId, mapId, boxId), msg)
|
2023-12-20 10:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 发送继电器状态数据
|
2024-01-11 10:24:56 +08:00
|
|
|
func (client *MqttClient) PubRCCState(simulationId string, mapId int32, msg *state_proto.PushedDevicesStatus) error {
|
2023-12-25 14:15:22 +08:00
|
|
|
return client.pub(GetRccTopic(simulationId, mapId), msg)
|
2023-12-20 10:37:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 发送站场图状态数据
|
2024-01-11 10:24:56 +08:00
|
|
|
func (client *MqttClient) PubSfpState(simulationId string, mapId int32, msg *state_proto.PushedDevicesStatus) error {
|
2023-12-25 14:15:22 +08:00
|
|
|
return client.pub(GetSfpTopic(simulationId, mapId), msg)
|
2023-11-16 16:54:23 +08:00
|
|
|
}
|
2024-03-19 08:28:50 +08:00
|
|
|
|
|
|
|
// 发送列车控制状态
|
2024-07-04 17:26:46 +08:00
|
|
|
func (client *MqttClient) PubTrainControlState(simulationId string, trainId string, msg *state_proto.TrainControlStateMsg) error {
|
2024-03-19 11:00:19 +08:00
|
|
|
return client.pub(GetTrainControlTopic(simulationId, trainId), msg)
|
2024-03-19 08:28:50 +08:00
|
|
|
}
|