mgr.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package mqtt
  2. import (
  3. "runtime/debug"
  4. "time"
  5. "github.com/sirupsen/logrus"
  6. "lc/common/util"
  7. )
  8. // OptType 消息发布/订阅方向
  9. type OptType uint8
  10. const (
  11. ToAll OptType = 0 // 同时发布到云端和边缘端
  12. ToCloud OptType = 1 // 仅云端
  13. ToEdge OptType = 2 // 仅边缘端
  14. )
  15. // MQTTMessage 队列中的消息
  16. type MQTTMessage struct {
  17. topic string
  18. payload string
  19. qos QOS
  20. tp OptType
  21. }
  22. // RestartFunc 协程 panic 后重建回调
  23. type RestartFunc func(fn func(args ...interface{}) interface{}, args ...interface{})
  24. // MQTTMgr 管理 Cloud/Edge 双客户端,支持异步队列发布
  25. type MQTTMgr struct {
  26. Cloud *MqttClient
  27. Edge *MqttClient
  28. Queue *util.MlQueue
  29. restartFn RestartFunc
  30. }
  31. // MQTTMgrConfig 管理器构造参数
  32. type MQTTMgrConfig struct {
  33. CloudServer string
  34. CloudClientID string
  35. CloudUser string
  36. CloudPassword string
  37. CloudTimeout uint
  38. CloudOnline BaseMqttOnline // nil 则使用 EmptyMqttOnline
  39. EdgeServer string
  40. EdgeClientID string
  41. EdgeUser string
  42. EdgePassword string
  43. EdgeTimeout uint
  44. EdgeOnline BaseMqttOnline // nil 则使用 EmptyMqttOnline
  45. }
  46. // NewMQTTMgr 创建 MQTT 管理器
  47. func NewMQTTMgr(cfg MQTTMgrConfig) *MQTTMgr {
  48. mgr := &MQTTMgr{
  49. Queue: util.NewQueue(2000),
  50. }
  51. if cfg.CloudOnline == nil {
  52. cfg.CloudOnline = &EmptyMqttOnline{}
  53. }
  54. if cfg.EdgeOnline == nil {
  55. cfg.EdgeOnline = &EmptyMqttOnline{}
  56. }
  57. if cfg.CloudServer != "" {
  58. mgr.Cloud = NewMqttClient(cfg.CloudServer, cfg.CloudClientID,
  59. cfg.CloudUser, cfg.CloudPassword, cfg.CloudTimeout, cfg.CloudOnline)
  60. }
  61. if cfg.EdgeServer != "" {
  62. mgr.Edge = NewMqttClient(cfg.EdgeServer, cfg.EdgeClientID,
  63. cfg.EdgeUser, cfg.EdgePassword, cfg.EdgeTimeout, cfg.EdgeOnline)
  64. }
  65. return mgr
  66. }
  67. // SetRestartFn 设置 panic 恢复后的协程重建回调
  68. func (o *MQTTMgr) SetRestartFn(fn RestartFunc) {
  69. o.restartFn = fn
  70. }
  71. // Subscribe 订阅主题,支持方向选择
  72. func (o *MQTTMgr) Subscribe(topic string, qos QOS, handler MessageHandler, tp OptType) {
  73. switch tp {
  74. case ToAll:
  75. if o.Cloud != nil {
  76. o.Cloud.Handle(topic, handler)
  77. _ = o.Cloud.Subscribe(topic, qos)
  78. }
  79. if o.Edge != nil {
  80. o.Edge.Handle(topic, handler)
  81. _ = o.Edge.Subscribe(topic, qos)
  82. }
  83. case ToCloud:
  84. if o.Cloud != nil {
  85. o.Cloud.Handle(topic, handler)
  86. _ = o.Cloud.Subscribe(topic, qos)
  87. }
  88. case ToEdge:
  89. if o.Edge != nil {
  90. o.Edge.Handle(topic, handler)
  91. _ = o.Edge.Subscribe(topic, qos)
  92. }
  93. }
  94. }
  95. // UnSubscribe 退订主题
  96. func (o *MQTTMgr) UnSubscribe(topic string, tp OptType) {
  97. switch tp {
  98. case ToAll:
  99. if o.Cloud != nil {
  100. _ = o.Cloud.Unsubscribe(topic)
  101. }
  102. if o.Edge != nil {
  103. _ = o.Edge.Unsubscribe(topic)
  104. }
  105. case ToCloud:
  106. if o.Cloud != nil {
  107. _ = o.Cloud.Unsubscribe(topic)
  108. }
  109. case ToEdge:
  110. if o.Edge != nil {
  111. _ = o.Edge.Unsubscribe(topic)
  112. }
  113. }
  114. }
  115. // Publish 异步发布(入队列)
  116. func (o *MQTTMgr) Publish(topic, payload string, qos QOS, tp OptType) {
  117. o.Queue.Put(&MQTTMessage{topic: topic, payload: payload, qos: qos, tp: tp})
  118. }
  119. // doPublish 底层同步发布
  120. func (o *MQTTMgr) doPublish(msg *MQTTMessage) error {
  121. var err error
  122. switch msg.tp {
  123. case ToAll:
  124. if o.Cloud != nil {
  125. err = o.Cloud.PublishString(msg.topic, msg.payload, msg.qos)
  126. }
  127. if o.Edge != nil {
  128. _ = o.Edge.PublishString(msg.topic, msg.payload, msg.qos)
  129. }
  130. case ToCloud:
  131. if o.Cloud != nil {
  132. err = o.Cloud.PublishString(msg.topic, msg.payload, msg.qos)
  133. }
  134. case ToEdge:
  135. if o.Edge != nil {
  136. err = o.Edge.PublishString(msg.topic, msg.payload, msg.qos)
  137. }
  138. }
  139. return err
  140. }
  141. // MQTTConnectMgr 连接保持协程(每 10 秒重连)
  142. func (o *MQTTMgr) MQTTConnectMgr(args ...interface{}) interface{} {
  143. for {
  144. time.Sleep(10 * time.Second)
  145. if o.Cloud != nil {
  146. o.Cloud.Connect()
  147. }
  148. if o.Edge != nil {
  149. o.Edge.Connect()
  150. }
  151. }
  152. }
  153. // MQTTMessageHandle 队列消费协程(带 RETRY)
  154. func (o *MQTTMgr) MQTTMessageHandle(args ...interface{}) interface{} {
  155. defer func() {
  156. if err := recover(); err != nil {
  157. logrus.Errorf("MQTTMgr.MQTTMessageHandle发生异常:%v", err)
  158. logrus.Errorf("MQTTMgr.MQTTMessageHandle发生异常,堆栈信息:%s", string(debug.Stack()))
  159. time.Sleep(time.Second)
  160. if o.restartFn != nil {
  161. o.restartFn(o.MQTTMessageHandle, args)
  162. }
  163. }
  164. }()
  165. for {
  166. if m, ok, _ := o.Queue.Get(); ok {
  167. if msg, ok := m.(*MQTTMessage); ok {
  168. for {
  169. if err := o.doPublish(msg); err != nil {
  170. logrus.Errorf("发布主题为%s的消息失败,原因:%s", msg.topic, err.Error())
  171. time.Sleep(time.Second)
  172. continue
  173. }
  174. break
  175. }
  176. }
  177. } else {
  178. time.Sleep(200 * time.Millisecond)
  179. }
  180. }
  181. }