github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/queue/mqtt/mqtt.go (about) 1 package mqtt 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "sync" 10 "time" 11 12 logger "github.com/sereiner/library/log" 13 "github.com/sereiner/library/net" 14 "github.com/sereiner/library/utility" 15 16 "github.com/sereiner/library/queue" 17 "github.com/yosssi/gmq/mqtt" 18 "github.com/yosssi/gmq/mqtt/client" 19 ) 20 21 // MQTTClient memcache配置文件 22 type MQTTClient struct { 23 servers []string 24 client *client.Client 25 once sync.Once 26 Logger *logger.Logger 27 lk sync.Mutex 28 connCh chan int 29 done bool 30 conf *queue.Config 31 } 32 33 //New 根据配置文件创建一个redis连接 34 func New(addrs []string, raw string) (m *MQTTClient, err error) { 35 m = &MQTTClient{servers: addrs, Logger: logger.GetSession("mqtt.publisher", logger.CreateSession())} 36 m.connCh = make(chan int, 1) 37 m.conf = &queue.Config{} 38 if err := json.Unmarshal([]byte(raw), &m.conf); err != nil { 39 return nil, err 40 } 41 cc, _, err := m.connect() 42 if err != nil { 43 return nil, err 44 } 45 m.client = cc 46 go m.reconnect() 47 return m, nil 48 } 49 50 func (c *MQTTClient) reconnect() { 51 for { 52 select { 53 case <-time.After(time.Second * 3): //延迟重连 54 select { 55 case <-c.connCh: 56 c.Logger.Debug("publisher与服务器断开连接,准备重连") 57 func() { 58 defer recover() 59 c.client.Disconnect() 60 c.client.Terminate() 61 }() 62 client, b, err := c.connect() 63 if err != nil { 64 c.Logger.Error("连接失败:", err) 65 } 66 if b { 67 c.Logger.Info("publisher成功连接到服务器") 68 c.client = client 69 } 70 default: 71 72 } 73 } 74 } 75 } 76 77 func (c *MQTTClient) connect() (*client.Client, bool, error) { 78 c.lk.Lock() 79 defer c.lk.Unlock() 80 cert, err := c.getCert(c.conf) 81 if err != nil { 82 return nil, false, err 83 } 84 cc := client.New(&client.Options{ 85 ErrorHandler: func(err error) { 86 select { 87 case c.connCh <- 1: //发送重连消息 88 default: 89 } 90 }, 91 }) 92 if err := cc.Connect(&client.ConnectOptions{ 93 Network: "tcp", 94 Address: c.conf.Addr, 95 UserName: []byte(c.conf.UserName), 96 Password: []byte(c.conf.Password), 97 ClientID: []byte(fmt.Sprintf("%s-%s", net.GetLocalIPAddress(), utility.GetGUID()[0:6])), 98 TLSConfig: cert, 99 PINGRESPTimeout: time.Second, 100 CleanSession: true, 101 KeepAlive: 3, 102 }); err != nil { 103 return nil, false, fmt.Errorf("连接失败:%v(%s-%s/%s)", err, c.conf.Addr, c.conf.UserName, c.conf.Password) 104 } 105 return cc, true, nil 106 } 107 func (c *MQTTClient) getCert(conf *queue.Config) (*tls.Config, error) { 108 if conf.CertPath == "" { 109 return nil, nil 110 } 111 b, err := ioutil.ReadFile(conf.CertPath) 112 if err != nil { 113 return nil, fmt.Errorf("读取证书失败:%s(%v)", conf.CertPath, err) 114 } 115 roots := x509.NewCertPool() 116 if ok := roots.AppendCertsFromPEM(b); !ok { 117 return nil, fmt.Errorf("failed to parse root certificate") 118 } 119 return &tls.Config{ 120 RootCAs: roots, 121 }, nil 122 } 123 124 // Push 向存于 key 的列表的尾部插入所有指定的值 125 func (c *MQTTClient) Push(key string, value string) error { 126 if c.done { 127 return fmt.Errorf("队列已关闭") 128 } 129 if key == "" { 130 return fmt.Errorf("队列名称不能为空") 131 } 132 if value == "" { 133 return fmt.Errorf("放入队列的数据不能为空") 134 } 135 return c.client.Publish(&client.PublishOptions{ 136 QoS: mqtt.QoS0, 137 TopicName: []byte(key), 138 Message: []byte(value), 139 }) 140 } 141 142 // Pop 移除并且返回 key 对应的 list 的第一个元素。 143 func (c *MQTTClient) Pop(key string) (string, error) { 144 return "", fmt.Errorf("mqtt不支持pop方法") 145 } 146 147 // Count 移除并且返回 key 对应的 list 的第一个元素。 148 func (c *MQTTClient) Count(key string) (int64, error) { 149 return 0, fmt.Errorf("mqtt不支持pop方法") 150 } 151 152 // Close 释放资源 153 func (c *MQTTClient) Close() error { 154 c.done = true 155 c.once.Do(func() { 156 c.client.Disconnect() 157 c.client.Terminate() 158 }) 159 return nil 160 } 161 162 type redisResolver struct { 163 } 164 165 func (s *redisResolver) Resolve(address []string, conf string) (queue.IQueue, error) { 166 return New(address, conf) 167 } 168 func init() { 169 queue.Register("mqtt", &redisResolver{}) 170 }