github.com/godaddy-x/freego@v1.0.156/amqp/publish.go (about) 1 package rabbitmq 2 3 import ( 4 "fmt" 5 DIC "github.com/godaddy-x/freego/common" 6 "github.com/godaddy-x/freego/utils" 7 "github.com/godaddy-x/freego/zlog" 8 "github.com/streadway/amqp" 9 "sync" 10 "time" 11 ) 12 13 var ( 14 publishMgrs = make(map[string]*PublishManager) 15 ) 16 17 type PublishManager struct { 18 mu0 sync.Mutex 19 mu sync.Mutex 20 conf AmqpConfig 21 conn *amqp.Connection 22 channels map[string]*PublishMQ 23 } 24 25 type PublishMQ struct { 26 mu sync.Mutex 27 ready bool 28 option *Option 29 channel *amqp.Channel 30 queue *amqp.Queue 31 } 32 33 type QueueData struct { 34 Name string 35 Consumers int 36 Messages int 37 } 38 39 func (self *PublishManager) InitConfig(input ...AmqpConfig) (*PublishManager, error) { 40 for _, v := range input { 41 if _, b := publishMgrs[v.DsName]; b { 42 return nil, utils.Error("rabbitmq publish init failed: [", v.DsName, "] exist") 43 } 44 if len(v.DsName) == 0 { 45 v.DsName = DIC.MASTER 46 } 47 publishMgr := &PublishManager{ 48 conf: v, 49 channels: make(map[string]*PublishMQ), 50 } 51 if _, err := publishMgr.Connect(); err != nil { 52 return nil, err 53 } 54 publishMgrs[v.DsName] = publishMgr 55 zlog.Printf("rabbitmq publish service【%s】has been started successful", v.DsName) 56 } 57 return self, nil 58 } 59 60 func (self *PublishManager) Client(ds ...string) (*PublishManager, error) { 61 dsName := DIC.MASTER 62 if len(ds) > 0 && len(ds[0]) > 0 { 63 dsName = ds[0] 64 } 65 return publishMgrs[dsName], nil 66 } 67 68 func NewPublish(ds ...string) (*PublishManager, error) { 69 return new(PublishManager).Client(ds...) 70 } 71 72 func (self *PublishManager) Connect() (*PublishManager, error) { 73 conn, err := ConnectRabbitMQ(self.conf) 74 if err != nil { 75 return nil, err 76 } 77 self.conn = conn 78 return self, nil 79 } 80 81 func (self *PublishManager) openChannel() (*amqp.Channel, error) { 82 self.mu.Lock() 83 defer self.mu.Unlock() 84 channel, err := self.conn.Channel() 85 if err != nil { 86 e, b := err.(*amqp.Error) 87 if b && e.Code == 504 { // 重连connection 88 if _, err := self.Connect(); err != nil { 89 return nil, err 90 } 91 } 92 return nil, err 93 } 94 return channel, nil 95 } 96 97 func (self *PublishManager) getChannel() *amqp.Channel { 98 index := 0 99 for { 100 if index > 0 { 101 zlog.Warn("rabbitmq publish trying to connect again", 0, zlog.Int("tried", index)) 102 } 103 channel, err := self.openChannel() 104 if err != nil { 105 zlog.Error("rabbitmq publish init Connection/Channel failed: ", 0, zlog.AddError(err)) 106 time.Sleep(2500 * time.Millisecond) 107 index++ 108 continue 109 } 110 return channel 111 } 112 } 113 114 func (self *PublishManager) Queue(data *MsgData) (*QueueData, error) { 115 pub, err := self.initQueue(data) 116 if err != nil { 117 return nil, err 118 } 119 return &QueueData{ 120 Name: pub.queue.Name, 121 Consumers: pub.queue.Consumers, 122 Messages: pub.queue.Messages}, nil 123 } 124 125 func (self *PublishManager) initQueue(data *MsgData) (*PublishMQ, error) { 126 if len(data.Option.Router) == 0 { 127 data.Option.Router = data.Option.Queue 128 } 129 if !utils.CheckInt(data.Option.SigTyp, 0, 1) { 130 data.Option.SigTyp = 1 131 } 132 if len(data.Option.SigKey) < 32 { 133 data.Option.SigKey = utils.AddStr(utils.GetLocalSecretKey(), self.conf.SecretKey) 134 } 135 if len(data.Nonce) == 0 { 136 data.Nonce = utils.RandStr(6) 137 } 138 chanKey := utils.AddStr(data.Option.Exchange, data.Option.Router, data.Option.Queue) 139 // 判断生成通道 140 pub, ok := self.channels[chanKey] 141 if ok { 142 return pub, nil 143 } 144 self.mu0.Lock() 145 defer self.mu0.Unlock() 146 pub, ok = self.channels[chanKey] 147 if !ok { 148 if len(data.Option.Kind) == 0 { 149 data.Option.Kind = direct 150 } 151 if len(data.Option.Router) == 0 { 152 data.Option.Router = data.Option.Queue 153 } 154 opt := &Option{ 155 Kind: data.Option.Kind, 156 Exchange: data.Option.Exchange, 157 Queue: data.Option.Queue, 158 Router: data.Option.Router, 159 SigTyp: data.Option.SigTyp, 160 } 161 pub = &PublishMQ{channel: self.getChannel(), option: opt} 162 if err := pub.prepareExchange(); err != nil { 163 return nil, err 164 } 165 if err := pub.prepareQueue(); err != nil { 166 return nil, err 167 } 168 pub.ready = true 169 self.channels[chanKey] = pub 170 self.listen(pub) 171 } 172 return pub, nil 173 } 174 175 func (self *PublishManager) listen(pub *PublishMQ) { 176 pub.mu.Lock() 177 defer pub.mu.Unlock() 178 if !pub.ready { // 重新连接channel 179 pub.channel = self.getChannel() 180 pub.ready = true 181 } 182 closeChan := make(chan bool, 1) 183 go func(chan<- bool) { 184 mqErr := make(chan *amqp.Error) 185 closeErr := <-pub.channel.NotifyClose(mqErr) 186 zlog.Error("rabbitmq publish connection/channel receive failed", 0, zlog.String("exchange", pub.option.Exchange), zlog.String("queue", pub.option.Queue), zlog.AddError(closeErr)) 187 closeChan <- true 188 }(closeChan) 189 190 go func(<-chan bool) { 191 for { 192 select { 193 case <-closeChan: 194 pub.ready = false 195 self.listen(pub) 196 zlog.Warn("rabbitmq publish received channel exception, successful reconnected", 0, zlog.String("exchange", pub.option.Exchange), zlog.String("queue", pub.option.Queue)) 197 return 198 } 199 } 200 }(closeChan) 201 } 202 203 func (self *PublishManager) Publish(exchange, queue string, dataType int64, content interface{}) error { 204 msg := &MsgData{ 205 Option: Option{ 206 Exchange: exchange, 207 Queue: queue, 208 }, 209 Type: dataType, 210 Content: content, 211 } 212 return self.PublishMsgData(msg) 213 } 214 215 func (self *PublishManager) PublishMsgData(data *MsgData) error { 216 if data == nil { 217 return utils.Error("publish data empty") 218 } 219 pub, err := self.initQueue(data) 220 if err != nil { 221 return err 222 } 223 // 数据加密模式 224 sigTyp := data.Option.SigTyp 225 sigKey := data.Option.SigKey 226 if len(sigKey) == 0 { 227 return utils.Error("rabbitmq publish data key is nil") 228 } 229 content, err := utils.ToJsonBase64(data.Content) 230 if err != nil { 231 return err 232 } 233 if len(content) == 0 { 234 return utils.Error("rabbitmq publish content is nil") 235 } 236 if sigTyp == 1 { 237 aesContent, err := utils.AesEncrypt(utils.Str2Bytes(content), sigKey, sigKey) 238 if err != nil { 239 return utils.Error("rabbitmq publish content aes encrypt failed: ", err) 240 } 241 content = aesContent 242 } 243 data.Content = content 244 data.Signature = utils.HMAC_SHA256(utils.AddStr(content, data.Nonce), sigKey, true) 245 data.Option.SigKey = "" 246 if _, err := pub.sendMessage(data); err != nil { 247 return err 248 } 249 return nil 250 } 251 252 func (self *PublishMQ) sendMessage(msg *MsgData) (bool, error) { 253 body, err := utils.JsonMarshal(msg) 254 if err != nil { 255 return false, err 256 } 257 data := amqp.Publishing{ContentType: "text/plain", Body: body} 258 if err := self.channel.Publish(self.option.Exchange, self.option.Router, false, false, data); err != nil { 259 return false, err 260 } 261 return true, nil 262 } 263 264 func (self *PublishMQ) prepareExchange() error { 265 zlog.Println(fmt.Sprintf("rabbitmq publish init [%s - %s] successful", self.option.Kind, self.option.Exchange)) 266 return self.channel.ExchangeDeclare(self.option.Exchange, self.option.Kind, true, false, false, false, nil) 267 } 268 269 func (self *PublishMQ) prepareQueue() error { 270 if len(self.option.Queue) == 0 { 271 return nil 272 } 273 if q, err := self.channel.QueueDeclare(self.option.Queue, true, false, false, false, nil); err != nil { 274 return err 275 } else { 276 self.queue = &q 277 } 278 if err := self.channel.QueueBind(self.option.Queue, self.option.Router, self.option.Exchange, false, nil); err != nil { 279 return err 280 } 281 return nil 282 }