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  }