def __init__(self, userid, pubsub, **routing): self._userid = userid #websocket connection self._closing = False self._pubsub = pubsub self._pikaclient = None self._channel = None self._consumers = [] self._fsm = Subfsm(self) self._tmpbound = False self._bound = False self._exchange = routing.get("exchange", None) self._exchangetype = routing.get("exchange_type", None) self._expire = routing.get("expire", None) self._queuename = routing.get("queuename", None) self._routings = routing.get("routings", []) self._tmp_queuename = routing.get("tmp_queuename", None) self._tmp_routings = routing.get("tmp_routings", []) if not self._tmp_queuename: self._tmpbound = True if not self._queuename: self._bound = True
class PikaConsumer(object): def __init__(self, userid, pubsub, **routing): self._userid = userid #websocket connection self._closing = False self._pubsub = pubsub self._pikaclient = None self._channel = None self._consumers = [] self._fsm = Subfsm(self) self._tmpbound = False self._bound = False self._exchange = routing.get("exchange", None) self._exchangetype = routing.get("exchange_type", None) self._expire = routing.get("expire", None) self._queuename = routing.get("queuename", None) self._routings = routing.get("routings", []) self._tmp_queuename = routing.get("tmp_queuename", None) self._tmp_routings = routing.get("tmp_routings", []) if not self._tmp_queuename: self._tmpbound = True if not self._queuename: self._bound = True def start(self): _logger.debug("start consumer %s " % self._userid) if not self._exchange or not self._exchangetype: _logger.error("exchange name or exchange type missed") return _logger.info("fire Subfsm.SUB_EVENT_START") self._fsm.fire_event(Subfsm.SUB_EVENT_START) def execstart(self): # get one rabbitmq connection self._pikaclient = SubConnectionMgr.connection() if self._pikaclient: self._pikaclient.addconsumer(self) #create the channel if the connection is opened if self._pikaclient.isconnected(): self.connect() else: _logger.debug("pika is not connected") def connect(self): _logger.debug("begin connect channel %s" % self._userid) #clear all the consumers before connect del self._consumers[:] self._pikaclient._connection.channel(self.__on_channel_open) def __on_channel_closed(self, channel, reply_code, reply_text): _logger.error("Channel %i was closed: (%s) %s" % (channel, reply_code, reply_text)) _logger.info("fire Subfsm.SUB_EVENT_DISCONNECTED") self._fsm.fire_event(Subfsm.SUB_EVENT_DISCONNECTED) def __clear_existconsumers(self): if len(self._channel.consumer_tags) == 0: _logger.info("there is no consumers on the channel") return _logger.info("find other consumers") def __on_channel_open(self, channel): _logger.debug("__on_channel_open %s" % self._userid) self._channel = channel self.__clear_existconsumers() self._channel.add_on_close_callback(self.__on_channel_closed) self._channel.add_on_cancel_callback(self.__on_consumer_cancelled) try: self._channel.exchange_declare(exchange = self._exchange, exchange_type = self._exchangetype, auto_delete = False, durable = False, callback = self.__on_exchange_declared) except Exception as e: _logger.error("exchange_declare error {0}".format(e)) def __on_exchange_declared(self, frame): _logger.debug("begin __on_exchange_declared %s" % self._userid) try: #declare queue if self._queuename: self._channel.queue_declare(auto_delete = False, queue = self._queuename, durable = False, exclusive = False, callback = self.__on_queue_declared) #declare temp queue if self._tmp_queuename: self._channel.queue_declare(auto_delete = True, queue = self._tmp_queuename, durable = False, exclusive = True, callback = self.__on_tmp_queue_declared) except Exception as e: _logger.error("queue_declare error {0}".format(e)) def __on_queue_declared(self, frame): _logger.debug("begin __on_queue_declared %s" % self._userid) lastbound = False for item in self._routings: if item == self._routings[-1]: lastbound = True try: _logger.info("bind %s" % item) self._channel.queue_bind(exchange = self._exchange, queue = self._queuename, routing_key = item, callback = lambda frame, lastbound = lastbound:self.__on_queue_bound(frame, lastbound)) except Exception as e: _logger.error("queue_bind error {0}".format(e)) def __on_queue_bound(self, frame, lastbound): _logger.debug("begin __on_queue_bound %s" % self._userid) try: consumer = self._channel.basic_consume(consumer_callback = self.__on_pika_message, queue = self._queuename, no_ack = False) self._consumers.append(consumer) self._pubsub.connected() except Exception as e: _logger.error("cosume error {0}".format(e)) if lastbound: self._bound = True self.__check_connected() def __on_tmp_queue_declared(self, frame): _logger.debug("begin __on_tmp_queue_declared %s" % self._userid) lastbound = False for item in self._tmp_routings: if item == self._tmp_routings[-1]: lastbound = True try: _logger.info("bind %s" % item) self._channel.queue_bind(exchange = self._exchange, queue = self._tmp_queuename, routing_key = item, callback = lambda frame, lastbound = lastbound: self.__on_tmp_queue_bound(frame, lastbound)) except Exception as e: _logger.error("queue_bind error {0}".format(e)) def __on_tmp_queue_bound(self, frame, lastbound): _logger.debug("begin __on_tmp_queue_bound %s" % self._userid) try: consumer = self._channel.basic_consume(consumer_callback = self.__on_tmp_pika_message, queue = self._tmp_queuename, no_ack = True) self._consumers.append(consumer) self._pubsub.connected() except Exception as e: _logger.error("cosume error {0}".format(e)) if lastbound: self._tmpbound = True self.__check_connected() def __check_connected(self): _logger.info("check connected bound = %s and tmpbound = %s" % (self._bound, self._tmpbound)) if self._bound and self._tmpbound: _logger.info("fire Subfsm.SUB_EVENT_CONNECTED") self._fsm.fire_event(Subfsm.SUB_EVENT_CONNECTED) def __on_pika_message(self, channel, method, header, body): _logger.debug("begin __on_pika_message %s %r" % (self._userid, body)) if self._pubsub: self._pubsub.add_msg(body) self._channel.basic_ack(method.delivery_tag) else: _logger.error("connection aready closed") self.execstop() def __on_tmp_pika_message(self, channel, method, header, body): _logger.debug("begin __on_tmp_pika_message %s %r" % (self._userid, body)) if self._pubsub: self._pubsub.add_tmpmsg(body) else: _logger.error("connection aready closed") self.execstop() def __on_consumer_cancelled(self, method_frame): _logger.info("consumer cancelled %s" % self._userid) #close normal do nothing if self._closing: return #cancelled by the pika, we will close the channel if self._channel: self._channel.close() def close(self): #close normal when user offline self._pubsub = None _logger.info("fire Subfsm.SUB_EVENT_STOP") self._fsm.fire_event(Subfsm.SUB_EVENT_STOP) def execstop(self): self._pubsub = None self._closing = True #cancel all the consumers for item in self._consumers: self._channel.basic_cancel(callback = self.__on_consumer_cancelled, consumer_tag = item) del self._consumers[:] #close channel if self._channel: self._channel.close() def isclosed(self): return self._closing