U
    ¸~Hjc\  ã                   @   s¾   d Z ddlmZ ddlmZmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZmZ dZG d	d
„ d
eƒZG dd„ deƒZG dd„ deƒZG dd„ dƒZG dd„ dee
ƒZddd
ddgZdS )ap  
Memcache client protocol. Memcached is a caching server, storing data in the
form of pairs key/value, and memcache is the protocol to talk with it.

To connect to a server, create a factory for L{MemCacheProtocol}::

    from twisted.internet import reactor, protocol
    from twisted.protocols.memcache import MemCacheProtocol, DEFAULT_PORT
    d = protocol.ClientCreator(reactor, MemCacheProtocol
        ).connectTCP("localhost", DEFAULT_PORT)
    def doSomething(proto):
        # Here you call the memcache operations
        return proto.set("mykey", "a lot of data")
    d.addCallback(doSomething)
    reactor.run()

All the operations of the memcache protocol are present, but
L{MemCacheProtocol.set} and L{MemCacheProtocol.get} are the more important.

See U{http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt} for
more information about the protocol.
é    )Údeque)ÚDeferredÚTimeoutErrorÚfail)ÚLineReceiver)ÚTimeoutMixin)Úlog)ÚnativeStringÚnetworkStringiË+  c                   @   s   e Zd ZdZdS )ÚNoSuchCommandzA
    Exception raised when a non existent command is called.
    N©Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   ú>/tmp/pip-unpacked-wheel-ewod1tgb/twisted/protocols/memcache.pyr   (   s   r   c                   @   s   e Zd ZdZdS )ÚClientErrorz1
    Error caused by an invalid client call.
    Nr   r   r   r   r   r   .   s   r   c                   @   s   e Zd ZdZdS )ÚServerErrorz*
    Problem happening on the server.
    Nr   r   r   r   r   r   4   s   r   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚCommanda8  
    Wrap a client action into an object, that holds the values used in the
    protocol.

    @ivar _deferred: the L{Deferred} object that will be fired when the result
        arrives.
    @type _deferred: L{Deferred}

    @ivar command: name of the command sent to the server.
    @type command: L{bytes}
    c                 K   s0   || _ tƒ | _| ¡ D ]\}}t| ||ƒ qdS )zß
        Create a command.

        @param command: the name of the command.
        @type command: L{bytes}

        @param kwargs: this values will be stored as attributes of the object
            for future use
        N)Úcommandr   Ú	_deferredÚitemsÚsetattr)Úselfr   ÚkwargsÚkÚvr   r   r   Ú__init__G   s    
zCommand.__init__c                 C   s   | j  |¡ dS )zB
        Shortcut method to fire the underlying deferred.
        N)r   Úcallback)r   Úvaluer   r   r   ÚsuccessV   s    zCommand.successc                 C   s   | j  |¡ dS )z5
        Make the underlying deferred fails.
        N)r   Zerrback)r   Úerrorr   r   r   r   \   s    zCommand.failN)r   r   r   r   r   r!   r   r   r   r   r   r   :   s   r   c                   @   sT  e Zd ZdZdZdZdRd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d„ Zdd „ Zd!d"„ Zd#d$„ Zd%d&„ Zd'd(„ Zd)d*„ Zd+d,„ ZdSd.d/„ZdTd0d1„Zd2d3„ ZdUd5d6„ZdVd7d8„ZdWd9d:„ZdXd;d<„Z d=d>„ Z!d?d@„ Z"dAdB„ Z#dYdCdD„Z$dZdEdF„Z%dGdH„ Z&d[dJdK„Z'dLdM„ Z(dNdO„ Z)dPdQ„ Z*dIS )\ÚMemCacheProtocola1  
    MemCache protocol: connect to a memcached server to store/retrieve values.

    @ivar persistentTimeOut: the timeout period used to wait for a response.
    @type persistentTimeOut: L{int}

    @ivar _current: current list of requests waiting for an answer from the
        server.
    @type _current: L{deque} of L{Command}

    @ivar _lenExpected: amount of data expected in raw mode, when reading for
        a value.
    @type _lenExpected: L{int}

    @ivar _getBuffer: current buffer of data, used to store temporary data
        when reading in raw mode.
    @type _getBuffer: L{list}

    @ivar _bufferLength: the total amount of bytes in C{_getBuffer}.
    @type _bufferLength: L{int}

    @ivar _disconnected: indicate if the connectionLost has been called or not.
    @type _disconnected: L{bool}
    éú   Fé<   c                 C   s*   t ƒ | _d| _d| _d| _| | _| _dS )zÓ
        Create the protocol.

        @param timeOut: the timeout to wait before detecting that the
            connection is dead and close it. It's expressed in seconds.
        @type timeOut: L{int}
        N)r   Ú_currentÚ_lenExpectedÚ
_getBufferÚ_bufferLengthÚpersistentTimeOutÚtimeOut)r   r+   r   r   r   r   €   s
    zMemCacheProtocol.__init__c                 C   s    | j r| j  ¡ }| |¡ q dS )zW
        Cancel all the outstanding commands, making them fail with C{reason}.
        N)r&   Úpopleftr   )r   ÚreasonÚcmdr   r   r   Ú_cancelCommandsŽ   s    
z MemCacheProtocol._cancelCommandsc                 C   s   |   tdƒ¡ | j ¡  dS )z:
        Close the connection in case of timeout.
        zConnection timeoutN)r/   r   Ú	transportZloseConnection©r   r   r   r   ÚtimeoutConnection–   s    z"MemCacheProtocol.timeoutConnectionc                 C   s    d| _ |  |¡ t | |¡ dS )z9
        Cause any outstanding commands to fail.
        TN)Ú_disconnectedr/   r   ÚconnectionLost)r   r-   r   r   r   r4   �   s    
zMemCacheProtocol.connectionLostc                 C   s"   | j s|  | j¡ t | |¡ dS )zA
        Override sendLine to add a timeout to response.
        N)r&   Ú
setTimeoutr*   r   ÚsendLine)r   Úliner   r   r   r6   ¥   s    zMemCacheProtocol.sendLinec                 C   sÀ   |   ¡  | j |¡ |  jt|ƒ7  _| j| jd kr¼d | j¡}|d| j… }|| jd d… }|}d| _d| _d| _| jd }|jr¬|j	|j
 \}}|||f|j	|j
< n||_|  |¡ dS )z)
        Collect data for a get.
        é   ó    Nr   )ÚresetTimeoutr(   Úappendr)   Úlenr'   Újoinr&   ÚmultipleÚvaluesÚ
currentKeyr    ZsetLineMode)r   ÚdataÚbufÚremÚvalr.   ÚflagsÚcasr   r   r   ÚrawDataReceived­   s"    
z MemCacheProtocol.rawDataReceivedc                 C   s   | j  ¡  d¡ dS )z?
        Manage a success response to a set operation.
        TN©r&   r,   r!   r1   r   r   r   Ú
cmd_STOREDÄ   s    zMemCacheProtocol.cmd_STOREDc                 C   s   | j  ¡  d¡ dS )zŠ
        Manage a specific 'not stored' response to a set operation: this is not
        an error, but some condition wasn't met.
        FNrH   r1   r   r   r   Úcmd_NOT_STOREDÊ   s    zMemCacheProtocol.cmd_NOT_STOREDc                 C   s´   | j  ¡ }|jdkrN|jr:dd„ |j ¡ D ƒ}| |¡ q°| |j|jf¡ nb|jdkr„|jrl| |j¡ q°| |j|j	|jf¡ n,|jdkrœ| |j¡ nt
d t|jƒ¡ƒ‚dS )zB
        This the end token to a get or a stat operation.
        ó   getc                 S   s    i | ]\}}||d d d… “qS )Nr8   r   )Ú.0ÚkeyrD   r   r   r   Ú
<dictcomp>Ø   s      z,MemCacheProtocol.cmd_END.<locals>.<dictcomp>ó   getsó   statsz%Unexpected END response to {} commandN)r&   r,   r   r>   r?   r   r!   rE   r    rF   ÚRuntimeErrorÚformatr	   )r   r.   r?   r   r   r   Úcmd_ENDÑ   s"    



ÿÿzMemCacheProtocol.cmd_ENDc                 C   s   | j  ¡  d¡ dS )z=
        Manage error response for incr/decr/delete.
        FNrH   r1   r   r   r   Úcmd_NOT_FOUNDê   s    zMemCacheProtocol.cmd_NOT_FOUNDc                 C   s®   | j d }|jdkr(| ¡ \}}}d}n| ¡ \}}}}t|ƒ| _g | _d| _|jr€||jkrft	dƒ‚||_
t|ƒ|g|j|< n"|j|kr’t	dƒ‚t|ƒ|_||_|  ¡  dS )z:
        Prepare the reading a value after a get.
        r   rK   r9   zUnexpected commands answer.N)r&   r   ÚsplitÚintr'   r(   r)   r>   ÚkeysrQ   r@   r?   rM   rE   rF   Z
setRawMode)r   r7   r.   rM   rE   ÚlengthrF   r   r   r   Ú	cmd_VALUEð   s$    





zMemCacheProtocol.cmd_VALUEc                 C   s(   | j d }| dd¡\}}||j|< dS )z-
        Reception of one stat line.
        r   ó    é   N)r&   rU   r?   )r   r7   r.   rM   rD   r   r   r   Úcmd_STAT	  s    
zMemCacheProtocol.cmd_STATc                 C   s   | j  ¡  |¡ dS )z%
        Read version token.
        NrH   )r   ZversionDatar   r   r   Úcmd_VERSION  s    zMemCacheProtocol.cmd_VERSIONc                 C   s$   t  d¡ | j ¡ }| tƒ ¡ dS )z7
        A non-existent command has been sent.
        zNon-existent command sent.N)r   Úerrr&   r,   r   r   )r   r.   r   r   r   Ú	cmd_ERROR  s    

zMemCacheProtocol.cmd_ERRORc                 C   s2   t |ƒ}t d| ¡ | j ¡ }| t|ƒ¡ dS )z0
        An invalid input as been sent.
        zInvalid input: N)Úreprr   r^   r&   r,   r   r   ©r   ZerrTextr.   r   r   r   Úcmd_CLIENT_ERROR  s    
z!MemCacheProtocol.cmd_CLIENT_ERRORc                 C   s2   t |ƒ}t d| ¡ | j ¡ }| t|ƒ¡ dS )z4
        An error has happened server-side.
        zServer error: N)r`   r   r^   r&   r,   r   r   ra   r   r   r   Úcmd_SERVER_ERROR(  s    
z!MemCacheProtocol.cmd_SERVER_ERRORc                 C   s   | j  ¡  d¡ dS )z>
        A delete command has completed successfully.
        TNrH   r1   r   r   r   Úcmd_DELETED1  s    zMemCacheProtocol.cmd_DELETEDc                 C   s   | j  ¡  d¡ dS )z6
        The last command has been completed.
        TNrH   r1   r   r   r   Úcmd_OK7  s    zMemCacheProtocol.cmd_OKc                 C   s   | j  ¡  d¡ dS )z5
        A C{checkAndSet} update has failed.
        FNrH   r1   r   r   r   Ú
cmd_EXISTS=  s    zMemCacheProtocol.cmd_EXISTSc                 C   sÂ   |   ¡  | dd¡d }t| dt|ƒ dƒ}|dk	rb| dd¡dd… }|rZ||d ƒ q®|ƒ  nL| dd¡}t| dt|ƒ dƒ}|dk	r’|ƒ  n| j ¡ }t|ƒ}| |¡ | js¾|  	d¡ dS )z8
        Receive line commands from the server.
        rZ   r[   r   Zcmd_Nó   _)
r:   rU   Úgetattrr	   Úreplacer&   r,   rV   r!   r5   )r   r7   Útokenr.   ÚargsrD   r   r   r   ÚlineReceivedC  s"    

zMemCacheProtocol.lineReceivedr[   c                 C   s   |   d||¡S )a¾  
        Increment the value of C{key} by given value (default to 1).
        C{key} must be consistent with an int. Return the new value.

        @param key: the key to modify.
        @type key: L{bytes}

        @param val: the value to increment.
        @type val: L{int}

        @return: a deferred with will be called back with the new value
            associated with the key (after the increment).
        @rtype: L{Deferred}
        s   incr©Ú	_incrdecr©r   rM   rD   r   r   r   Ú	increment`  s    zMemCacheProtocol.incrementc                 C   s   |   d||¡S )aà  
        Decrement the value of C{key} by given value (default to 1).
        C{key} must be consistent with an int. Return the new value, coerced to
        0 if negative.

        @param key: the key to modify.
        @type key: L{bytes}

        @param val: the value to decrement.
        @type val: L{int}

        @return: a deferred with will be called back with the new value
            associated with the key (after the decrement).
        @rtype: L{Deferred}
        s   decrrm   ro   r   r   r   Ú	decrementq  s    zMemCacheProtocol.decrementc                 C   s�   | j rttdƒƒS t|tƒs4ttdt|ƒ› d�ƒƒS t|ƒ| jkrNttdƒƒS d 	||dt
|ƒf g¡}|  |¡ t||d�}| j |¡ |jS )z1
        Internal wrapper for incr/decr.
        únot connectedúInvalid type for key: ú, expecting bytesúKey too longrZ   s   %d©rM   )r3   r   rQ   Ú
isinstanceÚbytesr   Útyper<   ÚMAX_KEY_LENGTHr=   rV   r6   r   r&   r;   r   )r   r.   rM   rD   ÚfullcmdÚcmdObjr   r   r   rn   ƒ  s    
ÿ
zMemCacheProtocol._incrdecrr   c                 C   s   |   d||||d¡S )a�  
        Replace the given C{key}. It must already exist in the server.

        @param key: the key to replace.
        @type key: L{bytes}

        @param val: the new value associated with the key.
        @type val: L{bytes}

        @param flags: the flags to store with the key.
        @type flags: L{int}

        @param expireTime: if different from 0, the relative time in seconds
            when the key will be deleted from the store.
        @type expireTime: L{int}

        @return: a deferred that will fire with C{True} if the operation has
            succeeded, and C{False} with the key didn't previously exist.
        @rtype: L{Deferred}
        s   replacer9   ©Ú_set©r   rM   rD   rE   Ú
expireTimer   r   r   ri   •  s    zMemCacheProtocol.replacec                 C   s   |   d||||d¡S )a„  
        Add the given C{key}. It must not exist in the server.

        @param key: the key to add.
        @type key: L{bytes}

        @param val: the value associated with the key.
        @type val: L{bytes}

        @param flags: the flags to store with the key.
        @type flags: L{int}

        @param expireTime: if different from 0, the relative time in seconds
            when the key will be deleted from the store.
        @type expireTime: L{int}

        @return: a deferred that will fire with C{True} if the operation has
            succeeded, and C{False} with the key already exists.
        @rtype: L{Deferred}
        s   addr9   r}   r   r   r   r   Úadd¬  s    zMemCacheProtocol.addc                 C   s   |   d||||d¡S )a9  
        Set the given C{key}.

        @param key: the key to set.
        @type key: L{bytes}

        @param val: the value associated with the key.
        @type val: L{bytes}

        @param flags: the flags to store with the key.
        @type flags: L{int}

        @param expireTime: if different from 0, the relative time in seconds
            when the key will be deleted from the store.
        @type expireTime: L{int}

        @return: a deferred that will fire with C{True} if the operation has
            succeeded.
        @rtype: L{Deferred}
        s   setr9   r}   r   r   r   r   ÚsetÃ  s    zMemCacheProtocol.setc                 C   s   |   d|||||¡S )am  
        Change the content of C{key} only if the C{cas} value matches the
        current one associated with the key. Use this to store a value which
        hasn't been modified since last time you fetched it.

        @param key: The key to set.
        @type key: L{bytes}

        @param val: The value associated with the key.
        @type val: L{bytes}

        @param cas: Unique 64-bit value returned by previous call of C{get}.
        @type cas: L{bytes}

        @param flags: The flags to store with the key.
        @type flags: L{int}

        @param expireTime: If different from 0, the relative time in seconds
            when the key will be deleted from the store.
        @type expireTime: L{int}

        @return: A deferred that will fire with C{True} if the operation has
            succeeded, C{False} otherwise.
        @rtype: L{Deferred}
        s   casr}   )r   rM   rD   rF   rE   r€   r   r   r   ÚcheckAndSetÚ  s    zMemCacheProtocol.checkAndSetc           
   	   C   sÜ   | j rttdƒƒS t|tƒs4ttdt|ƒ› d�ƒƒS t|ƒ| jkrNttdƒƒS t|tƒspttdt|ƒ› d�ƒƒS |r|d| }t|ƒ}d 	||t
d|||f ƒg¡| }|  |¡ |  |¡ t||||d�}	| j |	¡ |	jS )	z6
        Internal wrapper for setting values.
        rr   rs   rt   ru   zInvalid type for value: rZ   z%d %d %d)rM   rE   rX   )r3   r   rQ   rw   rx   r   ry   r<   rz   r=   r
   r6   r   r&   r;   r   )
r   r.   rM   rD   rE   r€   rF   rX   r{   r|   r   r   r   r~   ö  s4    
ÿ
ÿÿýÿ

zMemCacheProtocol._setc                 C   s   |   d||ddd¡S )aœ  
        Append given data to the value of an existing key.

        @param key: The key to modify.
        @type key: L{bytes}

        @param val: The value to append to the current value associated with
            the key.
        @type val: L{bytes}

        @return: A deferred that will fire with C{True} if the operation has
            succeeded, C{False} otherwise.
        @rtype: L{Deferred}
        s   appendr   r9   r}   ro   r   r   r   r;     s    zMemCacheProtocol.appendc                 C   s   |   d||ddd¡S )až  
        Prepend given data to the value of an existing key.

        @param key: The key to modify.
        @type key: L{bytes}

        @param val: The value to prepend to the current value associated with
            the key.
        @type val: L{bytes}

        @return: A deferred that will fire with C{True} if the operation has
            succeeded, C{False} otherwise.
        @rtype: L{Deferred}
        s   prependr   r9   r}   ro   r   r   r   Úprepend'  s    zMemCacheProtocol.prependc                 C   s   |   |g|d¡S )a¾  
        Get the given C{key}. It doesn't support multiple keys. If
        C{withIdentifier} is set to C{True}, the command issued is a C{gets},
        that will return the current identifier associated with the value. This
        identifier has to be used when issuing C{checkAndSet} update later,
        using the corresponding method.

        @param key: The key to retrieve.
        @type key: L{bytes}

        @param withIdentifier: If set to C{True}, retrieve the current
            identifier along with the value and the flags.
        @type withIdentifier: L{bool}

        @return: A deferred that will fire with the tuple (flags, value) if
            C{withIdentifier} is C{False}, or (flags, cas identifier, value)
            if C{True}.  If the server indicates there is no value
            associated with C{key}, the returned value will be L{None} and
            the returned flags will be C{0}.
        @rtype: L{Deferred}
        F©Ú_get)r   rM   ÚwithIdentifierr   r   r   Úget9  s    zMemCacheProtocol.getc                 C   s   |   ||d¡S )a  
        Get the given list of C{keys}.  If C{withIdentifier} is set to C{True},
        the command issued is a C{gets}, that will return the identifiers
        associated with each values. This identifier has to be used when
        issuing C{checkAndSet} update later, using the corresponding method.

        @param keys: The keys to retrieve.
        @type keys: L{list} of L{bytes}

        @param withIdentifier: If set to C{True}, retrieve the identifiers
            along with the values and the flags.
        @type withIdentifier: L{bool}

        @return: A deferred that will fire with a dictionary with the elements
            of C{keys} as keys and the tuples (flags, value) as values if
            C{withIdentifier} is C{False}, or (flags, cas identifier, value) if
            C{True}.  If the server indicates there is no value associated with
            C{key}, the returned values will be L{None} and the returned flags
            will be C{0}.
        @rtype: L{Deferred}

        @since: 9.0
        Tr…   )r   rW   r‡   r   r   r   ÚgetMultipleQ  s    zMemCacheProtocol.getMultiplec           	      C   sÞ   t |ƒ}| jrttdƒƒS |D ]H}t|tƒsHttdt|ƒ› d�ƒƒ  S t|ƒ| j	krttdƒƒ  S q|rrd}nd}d 
|g| ¡}|  |¡ |r´dd	„ |D ƒ}t|||d
d�}nt||d ddddd�}| j |¡ |jS )z>
        Helper method for C{get} and C{getMultiple}.
        rr   rs   rt   ru   rO   rK   rZ   c                 S   s   i | ]
}|d “qS ))r   r9   Nr   )rL   rM   r   r   r   rN   €  s      z)MemCacheProtocol._get.<locals>.<dictcomp>T)rW   r?   r>   r   Nr9   F)rM   r    rE   rF   r>   )Úlistr3   r   rQ   rw   rx   r   ry   r<   rz   r=   r6   r   r&   r;   r   )	r   rW   r‡   r>   rM   r.   r{   r?   r|   r   r   r   r†   k  s8    
ÿ
     ÿzMemCacheProtocol._getNc                 C   sL   |rd| }nd}| j r$ttdƒƒS |  |¡ tdi d�}| j |¡ |jS )aí  
        Get some stats from the server. It will be available as a dict.

        @param arg: An optional additional string which will be sent along
            with the I{stats} command.  The interpretation of this value by
            the server is left undefined by the memcache protocol
            specification.
        @type arg: L{None} or L{bytes}

        @return: a deferred that will fire with a L{dict} of the available
            statistics.
        @rtype: L{Deferred}
        s   stats rP   rr   )r?   ©r3   r   rQ   r6   r   r&   r;   r   )r   Úargr.   r|   r   r   r   Ústats‰  s    

zMemCacheProtocol.statsc                 C   s6   | j rttdƒƒS |  d¡ tdƒ}| j |¡ |jS )zª
        Get the version of the server.

        @return: a deferred that will fire with the string value of the
            version.
        @rtype: L{Deferred}
        rr   s   versionr‹   ©r   r|   r   r   r   Úversion¢  s    
zMemCacheProtocol.versionc                 C   s`   | j rttdƒƒS t|tƒs4ttdt|ƒ› d�ƒƒS |  d| ¡ td|d�}| j	 
|¡ |jS )a  
        Delete an existing C{key}.

        @param key: the key to delete.
        @type key: L{bytes}

        @return: a deferred that will be called back with C{True} if the key
            was successfully deleted, or C{False} if not.
        @rtype: L{Deferred}
        rr   rs   rt   s   delete s   deleterv   )r3   r   rQ   rw   rx   r   ry   r6   r   r&   r;   r   )r   rM   r|   r   r   r   Údelete±  s    
ÿzMemCacheProtocol.deletec                 C   s6   | j rttdƒƒS |  d¡ tdƒ}| j |¡ |jS )z·
        Flush all cached values.

        @return: a deferred that will be called back with C{True} when the
            operation has succeeded.
        @rtype: L{Deferred}
        rr   s	   flush_allr‹   rŽ   r   r   r   ÚflushAllÇ  s    
zMemCacheProtocol.flushAll)r%   )r[   )r[   )r   r   )r   r   )r   r   )r   r   )F)F)N)+r   r   r   r   rz   r3   r   r/   r2   r4   r6   rG   rI   rJ   rS   rT   rY   r\   r]   r_   rb   rc   rd   re   rf   rl   rp   rq   rn   ri   r�   r‚   rƒ   r~   r;   r„   rˆ   r‰   r†   r�   r�   r�   r‘   r   r   r   r   r#   c   sP   
		








r#   ÚDEFAULT_PORTN)r   Úcollectionsr   Ztwisted.internet.deferr   r   r   Ztwisted.protocols.basicr   Ztwisted.protocols.policiesr   Ztwisted.pythonr   Ztwisted.python.compatr	   r
   r’   Ú	Exceptionr   r   r   r   r#   Ú__all__r   r   r   r   Ú<module>   s,   )    yû