U
    W¨+d¤&  ã                   @   s”   d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZ G dd	„ d	eƒZG d
d„ deƒZG dd„ deƒZG dd„ deƒZdS )aX	  
SQS Message

A Message represents the data stored in an SQS queue.  The rules for what is allowed within an SQS
Message are here:

    http://docs.amazonwebservices.com/AWSSimpleQueueService/2008-01-01/SQSDeveloperGuide/Query_QuerySendMessage.html

So, at it's simplest level a Message just needs to allow a developer to store bytes in it and get the bytes
back out.  However, to allow messages to have richer semantics, the Message class must support the
following interfaces:

The constructor for the Message class must accept a keyword parameter "queue" which is an instance of a
boto Queue object and represents the queue that the message will be stored in.  The default value for
this parameter is None.

The constructor for the Message class must accept a keyword parameter "body" which represents the
content or body of the message.  The format of this parameter will depend on the behavior of the
particular Message subclass.  For example, if the Message subclass provides dictionary-like behavior to the
user the body passed to the constructor should be a dict-like object that can be used to populate
the initial state of the message.

The Message class must provide an encode method that accepts a value of the same type as the body
parameter of the constructor and returns a string of characters that are able to be stored in an
SQS message body (see rules above).

The Message class must provide a decode method that accepts a string of characters that can be
stored (and probably were stored!) in an SQS message and return an object of a type that is consistent
with the "body" parameter accepted on the class constructor.

The Message class must provide a __len__ method that will return the size of the encoded message
that would be stored in SQS based on the current state of the Message object.

The Message class must provide a get_body method that will return the body of the message in the
same format accepted in the constructor of the class.

The Message class must provide a set_body method that accepts a message body in the same format
accepted by the constructor of the class.  This method should alter to the internal state of the
Message object to reflect the state represented in the message body parameter.

The Message class must provide a get_body_encoded method that returns the current body of the message
in the format in which it would be stored in SQS.
é    N)ÚStringIO)Úsix)Ú
Attributes)ÚMessageAttributes)ÚSQSDecodeErrorc                   @   sr   e Zd ZdZddd„Zdd„ Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )Ú
RawMessagea  
    Base class for SQS messages.  RawMessage does not encode the message
    in any way.  Whatever you store in the body of the message is what
    will be written to SQS and whatever is returned from SQS is stored
    directly into the body of the message.
    NÚ c                 C   s@   || _ |  |¡ d | _d | _d | _t| ƒ| _t| ƒ| _d | _	d S ©N)
ÚqueueÚset_bodyÚidÚreceipt_handleÚmd5r   Ú
attributesr   Úmessage_attributesÚmd5_message_attributes)Úselfr
   Úbody© r   ú4/tmp/pip-unpacked-wheel-dlxw5sjy/boto/sqs/message.pyÚ__init__T   s    


zRawMessage.__init__c                 C   s   t |  | j¡ƒS r	   )ÚlenÚencodeÚ_body©r   r   r   r   Ú__len__^   s    zRawMessage.__len__c                 C   s    |dkr| j S |dkr| jS d S )NÚ	AttributeZMessageAttribute)r   r   )r   ÚnameÚattrsÚ
connectionr   r   r   ÚstartElementa   s
    zRawMessage.startElementc                 C   sd   |dkr|   |¡ nL|dkr$|| _n<|dkr4|| _n,|dkrD|| _n|dkrT|| _nt| ||ƒ d S )NZBodyZ	MessageIdZReceiptHandleZ	MD5OfBodyZMD5OfMessageAttributes)r   r   r   r   r   Úsetattr)r   r   Úvaluer   r   r   r   Ú
endElementh   s    zRawMessage.endElementc                 C   s   |   |  |  ¡ ¡¡ d S r	   )r   ÚdecodeÚget_body)r   r   r   r   r   ÚendNodev   s    zRawMessage.endNodec                 C   s   |S )z8Transform body object into serialized byte array format.r   ©r   r"   r   r   r   r   y   s    zRawMessage.encodec                 C   s   |S )z/Transform seralized byte array into any object.r   r'   r   r   r   r$   }   s    zRawMessage.decodec                 C   s
   || _ dS )z@Override the current body for this object, using decoded format.N©r   )r   r   r   r   r   r      s    zRawMessage.set_bodyc                 C   s   | j S r	   r(   r   r   r   r   r%   …   s    zRawMessage.get_bodyc                 C   s   |   |  ¡ ¡S )zí
        This method is really a semi-private method used by the Queue.write
        method when writing the contents of the message to SQS.
        You probably shouldn't need to call this method in the normal course of events.
        )r   r%   r   r   r   r   Úget_body_encodedˆ   s    zRawMessage.get_body_encodedc                 C   s   | j r| j  | ¡S d S r	   )r
   Zdelete_messager   r   r   r   Údelete   s    zRawMessage.deletec                 C   s    | j r| j j | j | j|¡ d S r	   )r
   r   Zchange_message_visibilityr   )r   Zvisibility_timeoutr   r   r   Úchange_visibility”   s
    þzRawMessage.change_visibility)Nr   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r    r#   r&   r   r$   r   r%   r)   r*   r+   r   r   r   r   r   L   s   

r   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚMessageaz  
    The default Message class used for SQS queues.  This class automatically
    encodes/decodes the message body using Base64 encoding to avoid any
    illegal characters in the message body.  See:

    https://forums.aws.amazon.com/thread.jspa?threadID=13067

    for details on why this is a good idea.  The encode/decode is meant to
    be transparent to the end-user.
    c                 C   s&   t |tjƒs| d¡}t |¡ d¡S ©Núutf-8)Ú
isinstancer   Úbinary_typer   Úbase64Ú	b64encoder$   r'   r   r   r   r   ¦   s    
zMessage.encodec                 C   s<   zt  | d¡¡ d¡}W n   tj d¡ | Y S X |S ©Nr2   úUnable to decode message)r5   Ú	b64decoder   r$   ÚbotoÚlogÚwarningr'   r   r   r   r$   «   s    
zMessage.decodeN)r,   r-   r.   r/   r   r$   r   r   r   r   r0   š   s   r0   c                       s|   e Zd ZdZd‡ fdd„	Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zdd„ Zddd„Z‡  ZS )Ú	MHMessageaX  
    The MHMessage class provides a message that provides RFC821-like
    headers like this:

    HeaderName: HeaderValue

    The encoding/decoding of this is handled automatically and after
    the message body has been read, the message instance can be treated
    like a mapping object, i.e. m['HeaderName'] would return 'HeaderValue'.
    Nc                    s*   |d ks|dkri }t t| ƒ ||¡ d S )Nr   )Úsuperr=   r   )r   r
   r   Z	xml_attrs©Ú	__class__r   r   r   ¿   s    zMHMessage.__init__c                 C   s|   z`i }t |ƒ}| ¡ }|r^| d¡}|d|… }||d d …  ¡ }| ¡ || ¡ < | ¡ }qW n   td| ƒ‚Y nX |S )Nú:r   é   r8   )r   ÚreadlineÚfindÚstripr   )r   r"   ÚmsgÚfpÚlineÚdelimÚkeyr   r   r   r$   Ä   s    
zMHMessage.decodec                 C   s.   d}|  ¡ D ]}|d|d |d f  }q|S )Nr   z%s: %s
r   rB   )Úitems)r   r"   ÚsÚitemr   r   r   r   Ó   s    zMHMessage.encodec                 C   s
   || j kS r	   r(   ©r   rJ   r   r   r   Ú__contains__Ù   s    zMHMessage.__contains__c                 C   s    || j kr| j | S t|ƒ‚d S r	   )r   ÚKeyErrorrN   r   r   r   Ú__getitem__Ü   s    

zMHMessage.__getitem__c                 C   s   || j |< |  | j ¡ d S r	   )r   r   )r   rJ   r"   r   r   r   Ú__setitem__â   s    
zMHMessage.__setitem__c                 C   s
   | j  ¡ S r	   )r   Úkeysr   r   r   r   rS   æ   s    zMHMessage.keysc                 C   s
   | j  ¡ S r	   )r   Úvaluesr   r   r   r   rT   é   s    zMHMessage.valuesc                 C   s
   | j  ¡ S r	   )r   rK   r   r   r   r   rK   ì   s    zMHMessage.itemsc                 C   s
   || j kS r	   r(   rN   r   r   r   Úhas_keyï   s    zMHMessage.has_keyc                 C   s   | j  |¡ |  | j ¡ d S r	   )r   Úupdater   )r   Údr   r   r   rV   ò   s    zMHMessage.updatec                 C   s   | j  ||¡S r	   )r   Úget)r   rJ   Údefaultr   r   r   rX   ö   s    zMHMessage.get)NNN)N)r,   r-   r.   r/   r   r$   r   rO   rQ   rR   rS   rT   rK   rU   rV   rX   Ú__classcell__r   r   r?   r   r=   ³   s   r=   c                       s,   e Zd ZdZ‡ fdd„Z‡ fdd„Z‡  ZS )ÚEncodedMHMessageaN  
    The EncodedMHMessage class provides a message that provides RFC821-like
    headers like this:

    HeaderName: HeaderValue

    This variation encodes/decodes the body of the message in base64 automatically.
    The message instance can be treated like a mapping object,
    i.e. m['HeaderName'] would return 'HeaderValue'.
    c                    sB   zt  | d¡¡ d¡}W n   td| ƒ‚Y nX tt| ƒ |¡S r7   )r5   r9   r   r$   r   r>   r[   r'   r?   r   r   r$     s
    zEncodedMHMessage.decodec                    s&   t t| ƒ |¡}t | d¡¡ d¡S r1   )r>   r[   r   r5   r6   r$   r'   r?   r   r   r     s    zEncodedMHMessage.encode)r,   r-   r.   r/   r$   r   rZ   r   r   r?   r   r[   ù   s   r[   )r/   r5   r:   Zboto.compatr   r   Zboto.sqs.attributesr   Zboto.sqs.messageattributesr   Zboto.exceptionr   Úobjectr   r0   r=   r[   r   r   r   r   Ú<module>   s   ,NF