def _on_connect(self): # if a password is specified, authenticate if self.password: self.send_command('AUTH', self.password) if nativestr(self.read_response()) != 'OK': raise AuthenticationError('Invalid Password') # if a database is specified, switch to it if self.db: self.send_command('SELECT', self.db) if nativestr(self.read_response()) != 'OK': raise ConnectionError('Invalid Database')
def handle_message(self, response, ignore_subscribe_messages=False): """ Parses a pub/sub message. If the channel or pattern was subscribed to with a message handler_or_queue, the handler_or_queue is invoked instead of a parsed message being returned. """ message_type = nativestr(response[0]) if message_type == 'pmessage': message = { 'type': message_type, 'pattern': response[1], 'channel': response[2], 'data': response[3] } else: message = { 'type': message_type, 'pattern': None, 'channel': response[1], 'data': response[2] } if message_type in self.PUBLISH_MESSAGE_TYPES: # Incoming message. # Find the queue or callable, and context that are associated with # the incoming pattern/channel-name. Create a BusMessage, and either # call the callable with that instance, or place the instance in the # queue: handler_or_queue = None if message_type == 'pmessage': try: (handler_or_queue, context) = self.patterns.get(message['pattern'], None) except TypeError: # No callable or queue associated with this pattern: return None else: try: (handler_or_queue, context) = self.channels.get(message['channel'], None) except TypeError: # No callable or queue associated with this channel name: return None # Make a bus object, setting isJsonContent to True. This will # have the BusMessage __init__() method try to parse the data # as a JSON message that has content/id/time fields. If the message # is not proper JSON, the BusMessage init function will just put # the data itself into the content field: busMsg = BusMessage(content=message['data'], topicName=message['channel'], isJsonContent=True, context=context) if isinstance(handler_or_queue, Queue.Queue): handler_or_queue.put(busMsg) else: try: handler_or_queue(busMsg) except TypeError: raise TypeError("Message delivery method for %s was neither a queue nor a callable: %s" %\ (busMsg.topicName, handler_or_queue)) return None elif message_type in self.UNSUBSCRIBE_MESSAGE_TYPES: # if this is an unsubscribe message, indicate that # (p)unsubscribe() method(s) may now remove the # subscription from memory: if message_type == 'punsubscribe': self.patterns.setUnsubscribeAckArrived() else: self.channels.setUnsubscribeAckArrived() if ignore_subscribe_messages or self.ignore_subscribe_messages: return None elif message_type in self.SUBSCRIBE_MESSAGE_TYPES: # this is a (p)subscribe message. ignore if we don't # want them, but let (p)subscribe() method(s) know that # the ack arrived: if message_type == 'psubscribe': self.patterns.setSubscribeAckArrived() else: self.channels.setSubscribeAckArrived() if ignore_subscribe_messages or self.ignore_subscribe_messages: return None return message
def parse_response(self, response=None, socket_buffer=None, encoding=None, block=True, timeout=None): ''' Given a full line of Redis wire protocol, parse that line, requesting additional lines if needed by requesting them from the passed-in socket_buffer. That object must provide a readline(block, timeout) method, else error. Examples for a response are: - *2 - subscribe - $9 This method is called recursively. :param response: one line of the wire protocol :type response: string :param socket_buffer: object that provides a readline(block, timeout) method :type socket_buffer: {SocketLineReader | OneShotConnection | ...} :returns: parsed response :rtype: [string] :raise TimeoutError ''' if encoding is None: encoding = self.connection.encoding if response is None: response = socket_buffer.readline(block=block, timeout=timeout) # Guard against closed or semi-closed sockets having # returned bad data: try: byte, response = byte_to_chr(response[0]), response[1:] except TypeError: # Ignore the badly formatted response: return None if byte not in ('-', '+', ':', '$', '*'): raise InvalidResponse("Protocol Error: %s, %s" % (str(byte), str(response))) # server returned an error if byte == '-': response = nativestr(response) error = self.parse_error(response) # if the error is a ConnectionError, raise immediately so the user # is notified if isinstance(error, ConnectionError): raise error # otherwise, we're dealing with a ResponseError that might belong # inside a pipeline response. the connection's read_response() # and/or the pipeline's execute() will raise this error if # necessary, so just return the exception instance here. return error # simple-string: response holds result: elif byte == '+': pass # int value elif byte == ':': response = long(response) # bulk response elif byte == '$': length = int(response) if length == -1: # Null string: return None response = socket_buffer.read(length) # multi-bulk response elif byte == '*': length = int(response) if length == -1: return None response = [self.parse_response(response=None, socket_buffer=socket_buffer, block=block, timeout=timeout, encoding=encoding) for _ in xrange(length)] if isinstance(response, bytes) and encoding: response = response.decode(encoding) #*********** #print('Response: %s' % byte + '|' + str(response)) #*********** return response