github.com/qxnw/lib4go@v0.0.0-20180426074627-c80c7e84b925/mq/mqtt/mqtt.consumer.go (about) 1 package mqtt 2 3 import ( 4 "net" 5 "strings" 6 "sync" 7 8 "errors" 9 10 proto "github.com/huin/mqtt" 11 "github.com/jeffallen/mqtt" 12 "github.com/qxnw/lib4go/concurrent/cmap" 13 "github.com/qxnw/lib4go/logger" 14 "github.com/qxnw/lib4go/mq" 15 xnet "github.com/qxnw/lib4go/net" 16 "github.com/zkfy/stompngo" 17 ) 18 19 type consumerChan struct { 20 msgChan <-chan stompngo.MessageData 21 unconsumeCh chan struct{} 22 } 23 24 //Consumer Consumer 25 type Consumer struct { 26 address string 27 client *mqtt.ClientConn 28 queues cmap.ConcurrentMap 29 subChan chan string 30 connecting bool 31 closeCh chan struct{} 32 done bool 33 lk sync.Mutex 34 header []string 35 once sync.Once 36 *mq.OptionConf 37 conf *Conf 38 } 39 40 //NewConsumer 创建新的Consumer 41 func NewConsumer(address string, opts ...mq.Option) (consumer *Consumer, err error) { 42 consumer = &Consumer{address: address} 43 consumer.OptionConf = &mq.OptionConf{Logger: logger.GetSession("mqtt", logger.CreateSession())} 44 consumer.closeCh = make(chan struct{}) 45 consumer.queues = cmap.New(2) 46 consumer.subChan = make(chan string, 3) 47 for _, opt := range opts { 48 opt(consumer.OptionConf) 49 } 50 consumer.conf, err = NewConf(consumer.Raw) 51 return 52 } 53 54 //Connect 连接服务器 55 func (consumer *Consumer) Connect() (err error) { 56 conn, err := net.Dial("tcp", consumer.conf.Address) 57 if err != nil { 58 return err 59 } 60 cc := mqtt.NewClientConn(conn) 61 cc.Dump = consumer.conf.DumpData 62 cc.ClientId = xnet.GetLocalIPAddress() 63 if err = cc.Connect(consumer.conf.UserName, consumer.conf.Password); err != nil { 64 return err 65 } 66 consumer.client = cc 67 go consumer.recvMessage() 68 return nil 69 } 70 71 //recvMessage 循环接收,并放入指定的队列 72 func (consumer *Consumer) recvMessage() { 73 74 START: 75 for { 76 select { 77 case <-consumer.closeCh: 78 break START 79 case q := <-consumer.subChan: 80 tq := make([]proto.TopicQos, 1) 81 tq[0].Topic = q 82 tq[0].Qos = proto.QosAtMostOnce 83 consumer.client.Subscribe(tq) 84 case msg := <-consumer.client.Incoming: 85 nmsg := NewMessage() 86 if err := msg.Payload.WritePayload(nmsg); err != nil { 87 consumer.Logger.Error(err) 88 continue 89 } 90 if nq, b := consumer.queues.Get(msg.TopicName); b { 91 nQ := nq.(chan *Message) 92 nQ <- nmsg 93 } 94 } 95 } 96 } 97 98 //Consume 注册消费信息 99 func (consumer *Consumer) Consume(queue string, concurrency int, callback func(mq.IMessage)) (err error) { 100 if strings.EqualFold(queue, "") { 101 return errors.New("队列名字不能为空") 102 } 103 if callback == nil { 104 return errors.New("回调函数不能为nil") 105 } 106 107 _, _, err = consumer.queues.SetIfAbsentCb(queue, func(input ...interface{}) (c interface{}, err error) { 108 queue := input[0].(string) 109 if concurrency <= 0 { 110 concurrency = 10 111 } 112 msgChan := make(chan *Message, concurrency) 113 for i := 0; i < concurrency; i++ { 114 go func() { 115 START: 116 for { 117 select { 118 case message, ok := <-msgChan: 119 if !ok { 120 break START 121 } 122 go callback(message) 123 } 124 } 125 }() 126 } 127 consumer.subChan <- queue 128 return msgChan, nil 129 }, queue) 130 return 131 } 132 133 //UnConsume 取消注册消费 134 func (consumer *Consumer) UnConsume(queue string) { 135 136 } 137 138 //Close 关闭当前连接 139 func (consumer *Consumer) Close() { 140 consumer.once.Do(func() { 141 close(consumer.closeCh) 142 }) 143 144 consumer.queues.RemoveIterCb(func(key string, value interface{}) bool { 145 ch := value.(chan *Message) 146 close(ch) 147 return true 148 }) 149 if consumer.client == nil { 150 return 151 } 152 consumer.client.Disconnect() 153 } 154 155 type ConsumerResolver struct { 156 } 157 158 func (s *ConsumerResolver) Resolve(address string, opts ...mq.Option) (mq.MQConsumer, error) { 159 return NewConsumer(address, opts...) 160 } 161 func init() { 162 mq.RegisterCosnumer("mqtt", &ConsumerResolver{}) 163 }