client_wrapper.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package mqtt
  2. import (
  3. "context"
  4. "fmt"
  5. "sync"
  6. "time"
  7. "github.com/sirupsen/logrus"
  8. )
  9. // BaseMqttOnline 上线消息和遗嘱消息接口
  10. type BaseMqttOnline interface {
  11. GetOnlineMsg() (string, string)
  12. GetWillMsg() (string, string)
  13. }
  14. // EmptyMqttOnline 空实现:不上线、无遗嘱
  15. type EmptyMqttOnline struct{}
  16. func (o *EmptyMqttOnline) GetOnlineMsg() (string, string) { return "", "" }
  17. func (o *EmptyMqttOnline) GetWillMsg() (string, string) { return "", "" }
  18. // MqttClient 封装 common/mqtt.Client,提供超时控制、主题记忆、断线自动重订阅
  19. type MqttClient struct {
  20. mqtt *Client
  21. mu sync.Mutex
  22. mapTopics map[string]QOS
  23. timeout uint
  24. MqttOnline BaseMqttOnline
  25. }
  26. // NewMqttClient 创建并连接 MQTT 客户端
  27. func NewMqttClient(server, clientID, user, password string, timeout uint, online BaseMqttOnline) *MqttClient {
  28. o := &MqttClient{
  29. mapTopics: make(map[string]QOS),
  30. timeout: timeout,
  31. MqttOnline: online,
  32. }
  33. client, err := NewClient(ClientOptions{
  34. Servers: []string{server},
  35. ClientID: clientID,
  36. Username: user,
  37. Password: password,
  38. AutoReconnect: true,
  39. }, o)
  40. if err != nil {
  41. panic(fmt.Errorf("MQTT错误: %w", err))
  42. }
  43. o.mqtt = client
  44. ctx, cancel := o.Ctx()
  45. defer cancel()
  46. _ = client.Connect(ctx)
  47. return o
  48. }
  49. // ---- 实现 ConnHandler 接口 ----
  50. func (o *MqttClient) ConnectionLostHandler(err error) {
  51. logrus.Errorln("MqttClient.ConnectionLostHandler:MQTT连接已经断开,原因:", err)
  52. }
  53. func (o *MqttClient) OnConnectHandler() {
  54. logrus.Infoln("MqttClient.OnConnectHandler:MQTT连接成功")
  55. for k, v := range o.mapTopics {
  56. if err := o.Subscribe(k, v); err != nil {
  57. logrus.Errorf("重订阅主题 %s 失败: %v", k, err)
  58. }
  59. }
  60. topic, str := o.MqttOnline.GetOnlineMsg()
  61. if topic != "" {
  62. if err := o.PublishString(topic, str, 1); err != nil {
  63. logrus.Errorf("发布上线消息失败: topic=%s, err=%v", topic, err)
  64. } else {
  65. logrus.Infof("发布上线消息成功: topic=%s", topic)
  66. }
  67. } else {
  68. logrus.Warnln("发布上线消息跳过: GetOnlineMsg返回空topic,请检查appConfig.GID是否已加载")
  69. }
  70. }
  71. func (o *MqttClient) GetWill() (string, string) {
  72. return o.MqttOnline.GetWillMsg()
  73. }
  74. // ---- 操作代理 ----
  75. func (o *MqttClient) Connect() error {
  76. if !o.mqtt.IsConnected() {
  77. ctx, cancel := o.Ctx()
  78. defer cancel()
  79. return o.mqtt.Connect(ctx)
  80. }
  81. return nil
  82. }
  83. func (o *MqttClient) IsConnected() bool { return o.mqtt.IsConnected() }
  84. func (o *MqttClient) Publish(topic string, payload []byte, qos QOS) error {
  85. ctx, cancel := o.Ctx()
  86. defer cancel()
  87. return o.mqtt.Publish(ctx, topic, payload, qos)
  88. }
  89. func (o *MqttClient) PublishString(topic string, payload string, qos QOS) error {
  90. ctx, cancel := o.Ctx()
  91. defer cancel()
  92. return o.mqtt.PublishString(ctx, topic, payload, qos)
  93. }
  94. func (o *MqttClient) PublishJSON(topic string, payload interface{}, qos QOS) error {
  95. ctx, cancel := o.Ctx()
  96. defer cancel()
  97. return o.mqtt.PublishJSON(ctx, topic, payload, qos)
  98. }
  99. func (o *MqttClient) Subscribe(topic string, qos QOS) error {
  100. o.mu.Lock()
  101. if _, ok := o.mapTopics[topic]; !ok {
  102. o.mapTopics[topic] = qos
  103. }
  104. o.mu.Unlock()
  105. ctx, cancel := o.Ctx()
  106. defer cancel()
  107. return o.mqtt.Subscribe(ctx, topic, qos)
  108. }
  109. func (o *MqttClient) Unsubscribe(topic string) error {
  110. o.mu.Lock()
  111. if _, ok := o.mapTopics[topic]; ok {
  112. delete(o.mapTopics, topic)
  113. }
  114. o.mu.Unlock()
  115. ctx, cancel := o.Ctx()
  116. defer cancel()
  117. return o.mqtt.Unsubscribe(ctx, topic)
  118. }
  119. func (o *MqttClient) Handle(topic string, handler MessageHandler) Route {
  120. return o.mqtt.Handle(topic, handler)
  121. }
  122. func (o *MqttClient) Ctx() (context.Context, context.CancelFunc) {
  123. return context.WithTimeout(context.Background(), time.Millisecond*time.Duration(o.timeout))
  124. }