|
@@ -1,4 +1,4 @@
|
|
|
-package main
|
|
|
|
|
|
|
+package mqtt
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
"context"
|
|
"context"
|
|
@@ -7,77 +7,80 @@ import (
|
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/sirupsen/logrus"
|
|
|
-
|
|
|
|
|
- "lc/common/mqtt"
|
|
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+// BaseMqttOnline 上线消息和遗嘱消息接口
|
|
|
type BaseMqttOnline interface {
|
|
type BaseMqttOnline interface {
|
|
|
GetOnlineMsg() (string, string)
|
|
GetOnlineMsg() (string, string)
|
|
|
GetWillMsg() (string, string)
|
|
GetWillMsg() (string, string)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-type EmptyMqttOnline struct {
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// EmptyMqttOnline 空实现:不上线、无遗嘱
|
|
|
|
|
+type EmptyMqttOnline struct{}
|
|
|
|
|
|
|
|
-func (o *EmptyMqttOnline) GetOnlineMsg() (string, string) {
|
|
|
|
|
- return "", ""
|
|
|
|
|
-}
|
|
|
|
|
-func (o *EmptyMqttOnline) GetWillMsg() (string, string) {
|
|
|
|
|
- return "", ""
|
|
|
|
|
-}
|
|
|
|
|
|
|
+func (o *EmptyMqttOnline) GetOnlineMsg() (string, string) { return "", "" }
|
|
|
|
|
+func (o *EmptyMqttOnline) GetWillMsg() (string, string) { return "", "" }
|
|
|
|
|
|
|
|
|
|
+// MqttClient 封装 common/mqtt.Client,提供超时控制、主题记忆、断线自动重订阅
|
|
|
type MqttClient struct {
|
|
type MqttClient struct {
|
|
|
- mqtt *mqtt.Client //
|
|
|
|
|
- mu sync.Mutex //保护mapTopics
|
|
|
|
|
- mapTopics map[string]mqtt.QOS //订阅的主题
|
|
|
|
|
- timeout uint //超时时间,毫秒为单位
|
|
|
|
|
- MqttOnline BaseMqttOnline //是否发布上线消息&遗嘱消息
|
|
|
|
|
|
|
+ mqtt *Client
|
|
|
|
|
+ mu sync.Mutex
|
|
|
|
|
+ mapTopics map[string]QOS
|
|
|
|
|
+ timeout uint
|
|
|
|
|
+ MqttOnline BaseMqttOnline
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func NewMqttClient(server, clientid, user, password string, timeout uint, mqttOnline BaseMqttOnline) *MqttClient {
|
|
|
|
|
- o := MqttClient{
|
|
|
|
|
- mapTopics: make(map[string]mqtt.QOS),
|
|
|
|
|
|
|
+// NewMqttClient 创建并连接 MQTT 客户端
|
|
|
|
|
+func NewMqttClient(server, clientID, user, password string, timeout uint, online BaseMqttOnline) *MqttClient {
|
|
|
|
|
+ o := &MqttClient{
|
|
|
|
|
+ mapTopics: make(map[string]QOS),
|
|
|
timeout: timeout,
|
|
timeout: timeout,
|
|
|
- MqttOnline: mqttOnline,
|
|
|
|
|
|
|
+ MqttOnline: online,
|
|
|
}
|
|
}
|
|
|
- client, err := mqtt.NewClient(mqtt.ClientOptions{
|
|
|
|
|
|
|
+ client, err := NewClient(ClientOptions{
|
|
|
Servers: []string{server},
|
|
Servers: []string{server},
|
|
|
- ClientID: clientid,
|
|
|
|
|
|
|
+ ClientID: clientID,
|
|
|
Username: user,
|
|
Username: user,
|
|
|
Password: password,
|
|
Password: password,
|
|
|
AutoReconnect: true,
|
|
AutoReconnect: true,
|
|
|
- }, &o)
|
|
|
|
|
|
|
+ }, o)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- panic(fmt.Sprintf("MQTT错误:", err.Error()))
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+ panic(fmt.Errorf("MQTT错误: %w", err))
|
|
|
}
|
|
}
|
|
|
o.mqtt = client
|
|
o.mqtt = client
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
- err = client.Connect(ctx)
|
|
|
|
|
- return &o
|
|
|
|
|
|
|
+ _ = client.Connect(ctx)
|
|
|
|
|
+ return o
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// ---- 实现 ConnHandler 接口 ----
|
|
|
|
|
+
|
|
|
func (o *MqttClient) ConnectionLostHandler(err error) {
|
|
func (o *MqttClient) ConnectionLostHandler(err error) {
|
|
|
logrus.Errorln("MqttClient.ConnectionLostHandler:MQTT连接已经断开,原因:", err)
|
|
logrus.Errorln("MqttClient.ConnectionLostHandler:MQTT连接已经断开,原因:", err)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (o *MqttClient) OnConnectHandler() {
|
|
func (o *MqttClient) OnConnectHandler() {
|
|
|
logrus.Infoln("MqttClient.OnConnectHandler:MQTT连接成功")
|
|
logrus.Infoln("MqttClient.OnConnectHandler:MQTT连接成功")
|
|
|
- //连接成功则订阅主题
|
|
|
|
|
for k, v := range o.mapTopics {
|
|
for k, v := range o.mapTopics {
|
|
|
- o.Subscribe(k, v)
|
|
|
|
|
|
|
+ if err := o.Subscribe(k, v); err != nil {
|
|
|
|
|
+ logrus.Errorf("重订阅主题 %s 失败: %v", k, err)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
topic, str := o.MqttOnline.GetOnlineMsg()
|
|
topic, str := o.MqttOnline.GetOnlineMsg()
|
|
|
if topic != "" {
|
|
if topic != "" {
|
|
|
- o.PublishString(topic, str, 0)
|
|
|
|
|
|
|
+ if err := o.PublishString(topic, str, 0); err != nil {
|
|
|
|
|
+ logrus.Errorf("发布上线消息失败: %v", err)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (o *MqttClient) GetWill() (topic string, payload string) {
|
|
|
|
|
|
|
+func (o *MqttClient) GetWill() (string, string) {
|
|
|
return o.MqttOnline.GetWillMsg()
|
|
return o.MqttOnline.GetWillMsg()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// ---- 操作代理 ----
|
|
|
|
|
+
|
|
|
func (o *MqttClient) Connect() error {
|
|
func (o *MqttClient) Connect() error {
|
|
|
if !o.mqtt.IsConnected() {
|
|
if !o.mqtt.IsConnected() {
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
@@ -87,32 +90,32 @@ func (o *MqttClient) Connect() error {
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (o *MqttClient) IsConnected() bool {
|
|
|
|
|
- return o.mqtt.IsConnected()
|
|
|
|
|
-}
|
|
|
|
|
|
|
+func (o *MqttClient) IsConnected() bool { return o.mqtt.IsConnected() }
|
|
|
|
|
|
|
|
-func (o *MqttClient) Publish(topic string, payload []byte, qos mqtt.QOS) error {
|
|
|
|
|
|
|
+func (o *MqttClient) Publish(topic string, payload []byte, qos QOS) error {
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
return o.mqtt.Publish(ctx, topic, payload, qos)
|
|
return o.mqtt.Publish(ctx, topic, payload, qos)
|
|
|
}
|
|
}
|
|
|
-func (o *MqttClient) PublishString(topic string, payload string, qos mqtt.QOS) error {
|
|
|
|
|
|
|
+
|
|
|
|
|
+func (o *MqttClient) PublishString(topic string, payload string, qos QOS) error {
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
return o.mqtt.PublishString(ctx, topic, payload, qos)
|
|
return o.mqtt.PublishString(ctx, topic, payload, qos)
|
|
|
}
|
|
}
|
|
|
-func (o *MqttClient) PublishJSON(topic string, payload interface{}, qos mqtt.QOS) error {
|
|
|
|
|
|
|
+
|
|
|
|
|
+func (o *MqttClient) PublishJSON(topic string, payload interface{}, qos QOS) error {
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
return o.mqtt.PublishJSON(ctx, topic, payload, qos)
|
|
return o.mqtt.PublishJSON(ctx, topic, payload, qos)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (o *MqttClient) Subscribe(topic string, qos mqtt.QOS) error {
|
|
|
|
|
|
|
+func (o *MqttClient) Subscribe(topic string, qos QOS) error {
|
|
|
o.mu.Lock()
|
|
o.mu.Lock()
|
|
|
- defer o.mu.Unlock()
|
|
|
|
|
if _, ok := o.mapTopics[topic]; !ok {
|
|
if _, ok := o.mapTopics[topic]; !ok {
|
|
|
o.mapTopics[topic] = qos
|
|
o.mapTopics[topic] = qos
|
|
|
}
|
|
}
|
|
|
|
|
+ o.mu.Unlock()
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
return o.mqtt.Subscribe(ctx, topic, qos)
|
|
return o.mqtt.Subscribe(ctx, topic, qos)
|
|
@@ -120,16 +123,16 @@ func (o *MqttClient) Subscribe(topic string, qos mqtt.QOS) error {
|
|
|
|
|
|
|
|
func (o *MqttClient) Unsubscribe(topic string) error {
|
|
func (o *MqttClient) Unsubscribe(topic string) error {
|
|
|
o.mu.Lock()
|
|
o.mu.Lock()
|
|
|
- defer o.mu.Unlock()
|
|
|
|
|
if _, ok := o.mapTopics[topic]; ok {
|
|
if _, ok := o.mapTopics[topic]; ok {
|
|
|
delete(o.mapTopics, topic)
|
|
delete(o.mapTopics, topic)
|
|
|
}
|
|
}
|
|
|
|
|
+ o.mu.Unlock()
|
|
|
ctx, cancel := o.Ctx()
|
|
ctx, cancel := o.Ctx()
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
return o.mqtt.Unsubscribe(ctx, topic)
|
|
return o.mqtt.Unsubscribe(ctx, topic)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (o *MqttClient) Handle(topic string, handler mqtt.MessageHandler) mqtt.Route {
|
|
|
|
|
|
|
+func (o *MqttClient) Handle(topic string, handler MessageHandler) Route {
|
|
|
return o.mqtt.Handle(topic, handler)
|
|
return o.mqtt.Handle(topic, handler)
|
|
|
}
|
|
}
|
|
|
|
|
|