def get_pending_messages(self, username = None): result = [] if username is None: return result username = str(username) connection = self._get_blocking_amqp_conn() try: channel = connection.channel() logger.debug("Connecting to %s ", username) channel.queue_declare(queue = username, durable = True, exclusive = False, auto_delete = False) while connection.is_open: method, header, body = channel.basic_get(queue = username) if method.NAME == 'Basic.GetEmpty': # queue empty, stop gathering. connection.close() return result else: result.append(body) #channel.basic_ack(delivery_tag=method.delivery_tag) except Exception, e: logger.error("Crapsticks: %s" % str(e))
def send_broadcast(self, message, username): """ Send a message to all queues associated with the username exchange (1:N)""" user_exchange_name = username conn = self._get_blocking_amqp_conn() try: channel = conn.channel() logger.debug("Declaring exchange '%s'", user_exchange_name) channel.exchange_declare( exchange=user_exchange_name, durable=True, type='fanout', ) # Send message to user exchange so all other clients receive it logger.debug("Publishing message to exchange '%s'", user_exchange_name) channel.basic_publish( exchange=user_exchange_name, routing_key='', body=message, properties=pika.BasicProperties( content_type='text/plain', ), ) except: logger.error("Error sending broadcast message") raise finally: logger.debug("Closing AMQP connection to broker") conn.disconnect()
def publish_message(self, message, token): """ send a message to a specific device. (1:1) """ conn = self._get_blocking_amqp_conn() try: channel = conn.channel() logger.debug("Declaring incoming exchange '%s'", self.incoming_exchange_name) channel.exchange_declare( exchange=self.incoming_exchange_name, durable=True, type='direct', ) logger.debug("Publishing message to exchange '%s'", self.incoming_exchange_name) channel.basic_publish( exchange=self.incoming_exchange_name, routing_key=token, body=message, properties=pika.BasicProperties( content_type="text/plain", ), ) except: logger.error("Error publishing message to exchange") raise finally: logger.debug("Disconnecting from message broker") conn.disconnect()
def queue_message(self, message, queue_name): """ send a message to a specific outbound queue (1:1) """ conn = self._get_blocking_amqp_conn() try: channel = conn.channel() logger.debug("Declaring queue '%s' on message broker", queue_name) channel.queue_declare(queue=queue_name) logger.debug("Sending message to queue '%s' for processing", queue_name) channel.basic_publish( exchange='', routing_key=queue_name, body=message, properties=pika.BasicProperties( content_type="text/plain", ), ) except: logger.error("Error queueing message in message broker") raise finally: logger.debug("Disconnecting from message broker") conn.disconnect()
def _delete_binding(self, source_exch, dest_exch, routing_key): http_conn = self._get_http_conn() try: auth_headers = { 'Authorization': 'Basic ' + base64.b64encode('%s:%s' % \ (self.broker_user, self.broker_pass) ), } path = '/api/bindings/%s/e/%s/e/%s/%s' % ( urllib.quote_plus(self.broker_vhost), urllib.quote_plus(source_exch), urllib.quote_plus(dest_exch), # Encode twice because binding "properties" are URL-encoded before stored urllib.quote_plus(urllib.quote_plus(routing_key)) ) logger.debug("Sending HTTP DELETE request to broker %s", path) http_conn.request('DELETE', path, '', auth_headers) response = http_conn.getresponse() logger.debug("Broker returned response with status %s", response.status) if response.status != httplib.NO_CONTENT: logger.error("Unexpected response status '%s'", response.status) raise Exception("Unexpected response status '%s'", response.status) except: logger.error("Error deleting binding via HTTP") raise finally: logger.debug("Closing HTTP connection to broker") http_conn.close()
def _ensure_exchanges_exist(self, incoming_exchange_name, user_exchange_name): conn = self._get_blocking_amqp_conn() try: channel = conn.channel() # TODO: Decide if we should remove this call; the incoming exchange # should always exist before new_subscription is called logger.debug("Declaring incoming exchange %s", incoming_exchange_name) channel.exchange_declare( exchange=incoming_exchange_name, durable=True, type='direct', ) # TODO: Decide if we should remove this call; the user exchange # should always exist before new_subscription is called logger.debug("Declaring user exchange %s", user_exchange_name) channel.exchange_declare( exchange=user_exchange_name, durable=True, type='fanout', ) except: logger.error("Error ensuring exchanges exist on broker") raise finally: logger.debug("Closing AMQP connection to broker") conn.disconnect()
def create_client_queue(self, username): user_exchange_name = username # Create a unique client id to also be used as the name of the queue client_queue_name = "%x" % random.getrandbits(256) logger.info("Creating queue %s for user %s", client_queue_name, username) # Create the user exchange (if it doesn't already exist) and a client # queue with the generated name. conn = self._get_amqp_conn() try: channel = conn.channel() logger.debug("Declaring exchange %s", user_exchange_name) channel.exchange_declare( exchange=user_exchange_name, durable=True, type='fanout', ) logger.debug("Declaring queue %s", client_queue_name) channel.queue_declare(queue=client_queue_name, durable=True) logger.debug("Binding queue %s to exchange %s", client_queue_name, user_exchange_name, ) channel.queue_bind( exchange=user_exchange_name, queue=client_queue_name, ) except: logger.error("Error creating new client queue") raise finally: logger.debug("Closing AMQP connection to broker") conn.disconnect() return { 'queue_id': client_queue_name, 'host': self.broker_host, 'port': self.broker_amqp_port, }
def _add_binding(self, source_exch, dest_exch, routing_key): # XXX: OH EM GEE this is a hack. Creating Exchange-to-exchange (E2E) # bindings is a RabbitMQ-specific extension, so the pika AMQP # client doesn't support it. The RabbitMQ REST API does however, # so we do a quick HTTP POST here to create the binding. # # To do this properly, we'll probably have to roll our own version # of Pika which supports the exchange.bind method call. http_conn = self._get_http_conn() try: auth_headers = { 'Authorization': 'Basic ' + base64.b64encode('%s:%s' % \ (self.broker_user, self.broker_pass) ), 'Content-Type': 'application/json', } path = '/api/bindings/%s/e/%s/e/%s' % ( urllib.quote_plus(self.broker_vhost), urllib.quote_plus(source_exch), urllib.quote_plus(dest_exch) ) body = json.dumps({'routing_key': routing_key, 'arguments': []}) logger.debug("Sending HTTP POST request to broker %s", path) http_conn.request('POST', path, body, auth_headers) response = http_conn.getresponse() logger.debug("Broker returned response with status %s", response.status) if response.status != httplib.CREATED: logger.error("Unexpected response status '%s'", response.status) raise Exception("Unexpected response status '%s'", response.status) except: logger.error("Error adding binding via HTTP") raise finally: logger.debug("Closing HTTP connection to broker") http_conn.close()
def create_client_queue(self, username): self.channel_info = {} self.channel_info['exchange_name'] = username self.channel_info['queue_name'] = new_token() # Create a unique client id to also be used as the name of the queue client_queue_name = new_token() logger.info("Creating queue %s for user %s", self.channel_info.get('queue_name'), self.channel_info.get('exchange_name')) # Create the user exchange (if it doesn't already exist) and a client # queue with the generated name. conn = self._get_blocking_amqp_conn() try: channel = conn.channel() logger.debug("Declaring exchange %s", self.channel_info.get('exchange_name')) channel.exchange_declare( exchange=self.channel_info.get('exchange_name'), durable=True, type='fanout', ) logger.debug("Declaring queue %s", client_queue_name) channel.queue_declare(queue=client_queue_name, durable=True) logger.debug("Binding queue %s to exchange %s", client_queue_name, self.channel_info.get('exchange_name'), ) channel.queue_bind( exchange=self.channel_info.get('exchange_name'), queue=client_queue_name, ) except Exception, e: logger.error("Error creating new client queue. %s" % e.message) raise NotifStorageException('Cannot create new client')
logger.debug("Declaring queue %s", client_queue_name) channel.queue_declare(queue=client_queue_name, durable=True) logger.debug("Binding queue %s to exchange %s", client_queue_name, self.channel_info.get('exchange_name'), ) channel.queue_bind( exchange=self.channel_info.get('exchange_name'), queue=client_queue_name, ) except Exception, e: logger.error("Error creating new client queue. %s" % e.message) raise NotifStorageException('Cannot create new client') finally: logger.debug("Closing AMQP connection to broker") conn.disconnect() return { 'queue_id': client_queue_name, 'host': self.broker_host, 'port': self.broker_amqp_port, } def create_subscription(self, username, token): user_exchange_name = username # TODO: See if we can remove this call entirely self._ensure_exchanges_exist(self.incoming_exchange_name, user_exchange_name)
index_record = self.redis.lindex("u2m:%s" % username, 0) if index_record is not None: top_index = json.loads(index_record).get("id", 0) parsed_message = json.loads(message) message_body = json.loads(parsed_message.get('body')) now = int(time.time()) timestamp = parsed_message.get('timestamp', int(time.time())) if timestamp > now: timestamp == now redStore = {'file': doc_file, 'origin': origin, 'expry': int(timestamp + message_body.get('ttl', self.config.get('notifserver.max_ttl_seconds', 259200))), 'id': top_index + 1} logger.debug('Adding message for %s' % username) self.redis.lpush("u2m:%s" % username, json.dumps(redStore)) info = self.redis.hgetall("sin:%s:%s" % (username, queue)) info.update({'lastmsg': time.time(), 'lastorigin': origin}) self.redis.hmset("sin:%s:%s" % (username, queue), info) old = self.redis.lrange("u2m:%s" % username, 0, 0-max_msgs) if len(old): for message in old: self._cleanMessage(username, message) self.redis.ltrim("u2m:%s" % username, 0, max_msgs) return {"id": top_index + 1} def get_pending_messages(self, username, since = None): """ send messages to user """ doc_path = self._user_storage_path(username)