o
    ¯bc\  ã                   @   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g d¢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                   @   ó   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   ú</usr/lib/python3/dist-packages/twisted/protocols/memcache.pyr   (   ó    r   c                   @   r   )ÚClientErrorz1
    Error caused by an invalid client call.
    Nr   r   r   r   r   r   .   r   r   c                   @   r   )ÚServerErrorz*
    Problem happening on the server.
    Nr   r   r   r   r   r   4   r   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   ó   | j  |¡ dS )zB
        Shortcut method to fire the underlying deferred.
        N)r   Úcallback)r   Úvaluer   r   r   ÚsuccessV   ó   zCommand.successc                 C   r!   )z5
        Make the underlying deferred fails.
        N)r   Úerrback)r   Úerrorr   r   r   r   \   r%   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dSd0d1„Zd2d3„ ZdTd5d6„ZdTd7d8„ZdTd9d:„ZdTd;d<„Z d=d>„ Z!d?d@„ Z"dAdB„ Z#dUdCdD„Z$dUdEdF„Z%dGdH„ Z&dVdJdK„Z'dLdM„ Z(dNdO„ Z)dPdQ„ Z*dIS )WÚ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   r0   r   r   r   r    €   s
   zMemCacheProtocol.__init__c                 C   s(   | j r| j  ¡ }| |¡ | j sdS 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)r4   r   Ú	transportÚloseConnection©r   r   r   r   ÚtimeoutConnection–   s   z"MemCacheProtocol.timeoutConnectionc                 C   s    d| _ |  |¡ t | |¡ dS )z9
        Cause any outstanding commands to fail.
        TN)Ú_disconnectedr4   r   ÚconnectionLost)r   r2   r   r   r   r:   �   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   r<   ¥   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rV|j	|j
 \}}|||f|j	|j
< n||_|  |¡ dS dS )z)
        Collect data for a get.
        é   ó    Nr   )ÚresetTimeoutr-   Úappendr.   Úlenr,   Újoinr+   ÚmultipleÚvaluesÚ
currentKeyr#   ÚsetLineMode)r   ÚdataÚbufÚremÚvalr3   ÚflagsÚcasr   r   r   ÚrawDataReceived­   s$   
òz MemCacheProtocol.rawDataReceivedc                 C   ó   | j  ¡  d¡ dS )z?
        Manage a success response to a set operation.
        TN©r+   r1   r$   r7   r   r   r   Ú
cmd_STOREDÄ   ó   zMemCacheProtocol.cmd_STOREDc                 C   rO   )zŠ
        Manage a specific 'not stored' response to a set operation: this is not
        an error, but some condition wasn't met.
        FNrP   r7   r   r   r   Úcmd_NOT_STOREDÊ   s   zMemCacheProtocol.cmd_NOT_STOREDc                 C   sº   | j  ¡ }|jdkr)|jrdd„ |j ¡ D ƒ}| |¡ dS | |j|jf¡ dS |jdkrF|jr9| |j¡ dS | |j|j	|jf¡ dS |jdkrS| |j¡ dS t
d t|jƒ¡ƒ‚)zB
        This the end token to a get or a stat operation.
        ó   getc                 S   s    i | ]\}}||d d d… “qS )Nr>   r   )Ú.0ÚkeyrK   r   r   r   Ú
<dictcomp>Ø   s     z,MemCacheProtocol.cmd_END.<locals>.<dictcomp>ó   getsó   statsz%Unexpected END response to {} commandN)r+   r1   r   rD   rE   r   r$   rL   r#   rM   ÚRuntimeErrorÚformatr	   )r   r3   rE   r   r   r   Úcmd_ENDÑ   s"   



ÿÿzMemCacheProtocol.cmd_ENDc                 C   rO   )z=
        Manage error response for incr/decr/delete.
        FNrP   r7   r   r   r   Úcmd_NOT_FOUNDê   rR   zMemCacheProtocol.cmd_NOT_FOUNDc                 C   s®   | j d }|jdkr| ¡ \}}}d}n| ¡ \}}}}t|ƒ| _g | _d| _|jr@||jvr3t	dƒ‚||_
t|ƒ|g|j|< n|j|krIt	dƒ‚t|ƒ|_||_|  ¡  dS )z:
        Prepare the reading a value after a get.
        r   rT   r?   zUnexpected commands answer.N)r+   r   ÚsplitÚintr,   r-   r.   rD   ÚkeysrZ   rF   rE   rV   rL   rM   Ú
setRawMode)r   r=   r3   rV   rL   ÚlengthrM   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+   r^   rE   )r   r=   r3   rV   rK   r   r   r   Úcmd_STAT	  s   
zMemCacheProtocol.cmd_STATc                 C   s   | j  ¡  |¡ dS )z%
        Read version token.
        NrP   )r   ÚversionDatar   r   r   Úcmd_VERSION  rR   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+   r1   r   r   )r   r3   r   r   r   Ú	cmd_ERROR  s   

zMemCacheProtocol.cmd_ERRORc                 C   ó2   t |ƒ}t d| ¡ | j ¡ }| t|ƒ¡ dS )z0
        An invalid input as been sent.
        zInvalid input: N)Úreprr   ri   r+   r1   r   r   ©r   ÚerrTextr3   r   r   r   Úcmd_CLIENT_ERROR  ó   
z!MemCacheProtocol.cmd_CLIENT_ERRORc                 C   rk   )z4
        An error has happened server-side.
        zServer error: N)rl   r   ri   r+   r1   r   r   rm   r   r   r   Úcmd_SERVER_ERROR(  rp   z!MemCacheProtocol.cmd_SERVER_ERRORc                 C   rO   )z>
        A delete command has completed successfully.
        TNrP   r7   r   r   r   Úcmd_DELETED1  rR   zMemCacheProtocol.cmd_DELETEDc                 C   rO   )z6
        The last command has been completed.
        TNrP   r7   r   r   r   Úcmd_OK7  rR   zMemCacheProtocol.cmd_OKc                 C   rO   )z5
        A C{checkAndSet} update has failed.
        FNrP   r7   r   r   r   Ú
cmd_EXISTS=  rR   zMemCacheProtocol.cmd_EXISTSc                 C   sÆ   |   ¡  | dd¡d }t| dt|ƒ dƒ}|dur1| dd¡dd… }|r-||d ƒ n*|ƒ  n&| dd¡}t| dt|ƒ dƒ}|durI|ƒ  n| j ¡ }t|ƒ}| |¡ | jsa|  	d¡ dS dS )z8
        Receive line commands from the server.
        rd   re   r   Úcmd_Nó   _)
r@   r^   Úgetattrr	   Úreplacer+   r1   r_   r$   r;   )r   r=   Útokenr3   ÚargsrK   r   r   r   ÚlineReceivedC  s$   

þzMemCacheProtocol.lineReceivedre   c                 C   ó   |   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   rV   rK   r   r   r   Ú	increment`  s   zMemCacheProtocol.incrementc                 C   r|   )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   decrr}   r   r   r   r   Ú	decrementq  s   zMemCacheProtocol.decrementc                 C   s�   | j r	ttdƒƒS t|tƒsttdt|ƒ› d�ƒƒS t|ƒ| jkr't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 longrd   s   %d©rV   )r9   r   rZ   Ú
isinstanceÚbytesr   ÚtyperB   ÚMAX_KEY_LENGTHrC   r_   r<   r   r+   rA   r   )r   r3   rV   rK   ÚfullcmdÚcmdObjr   r   r   r~   ƒ  s   
ÿ
zMemCacheProtocol._incrdecrr   c                 C   ó   |   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   replacer?   ©Ú_set©r   rV   rK   rL   Ú
expireTimer   r   r   rx   •  ó   zMemCacheProtocol.replacec                 C   r�   )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   addr?   rŽ   r�   r   r   r   Úadd¬  r’   zMemCacheProtocol.addc                 C   r�   )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   setr?   rŽ   r�   r   r   r   ÚsetÃ  r’   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   rV   rK   rM   rL   r‘   r   r   r   ÚcheckAndSetÚ  s   zMemCacheProtocol.checkAndSetc           
   	   C   sÜ   | j r	ttdƒƒS t|tƒsttdt|ƒ› d�ƒƒS t|ƒ| jkr'ttdƒƒS t|tƒs8ttdt|ƒ› d�ƒƒS |r>d| }t|ƒ}d 	||t
d|||f ƒg¡| }|  |¡ |  |¡ t||||d�}	| j |	¡ |	jS )	z6
        Internal wrapper for setting values.
        r‚   rƒ   r„   r…   zInvalid type for value: rd   z%d %d %d)rV   rL   rb   )r9   r   rZ   r‡   rˆ   r   r‰   rB   rŠ   rC   r
   r<   r   r+   rA   r   )
r   r3   rV   rK   rL   r‘   rM   rb   r‹   rŒ   r   r   r   r�   ö  s4   
ÿ
ÿÿýÿ

zMemCacheProtocol._setc                 C   ó   |   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   r?   rŽ   r   r   r   r   rA     ó   zMemCacheProtocol.appendc                 C   r–   )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   r?   rŽ   r   r   r   r   Úprepend'  r—   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   rV   Ú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   r`   r›   r   r   r   ÚgetMultipleQ  s   zMemCacheProtocol.getMultiplec           	      C   sÞ   t |ƒ}| jrttdƒƒS |D ]$}t|tƒs$ttdt|ƒ› d�ƒƒ  S t|ƒ| j	kr3ttdƒƒ  S q|r9d}nd}d 
|g| ¡}|  |¡ |rZd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}.
        r‚   rƒ   r„   r…   rX   rT   rd   c                 S   s   i | ]}|d “qS ))r   r?   Nr   )rU   rV   r   r   r   rW   €  s    z)MemCacheProtocol._get.<locals>.<dictcomp>T)r`   rE   rD   r   Nr?   F)rV   r#   rL   rM   rD   )Úlistr9   r   rZ   r‡   rˆ   r   r‰   rB   rŠ   rC   r<   r   r+   rA   r   )	r   r`   r›   rD   rV   r3   r‹   rE   rŒ   r   r   r   rš   k  s0   
ÿÿ
ÿ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 rY   r‚   )rE   ©r9   r   rZ   r<   r   r+   rA   r   )r   Úargr3   rŒ   r   r   r   Ústats‰  s   

zMemCacheProtocol.statsc                 C   ó6   | 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}
        r‚   s   versionrŸ   ©r   rŒ   r   r   r   Úversion¢  ó   
zMemCacheProtocol.versionc                 C   s`   | j r	ttdƒƒS t|tƒst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}
        r‚   rƒ   r„   s   delete s   deleter†   )r9   r   rZ   r‡   rˆ   r   r‰   r<   r   r+   rA   r   )r   rV   rŒ   r   r   r   Údelete±  s   
ÿzMemCacheProtocol.deletec                 C   r¢   )z·
        Flush all cached values.

        @return: a deferred that will be called back with C{True} when the
            operation has succeeded.
        @rtype: L{Deferred}
        r‚   s	   flush_allrŸ   r£   r   r   r   ÚflushAllÇ  r¥   zMemCacheProtocol.flushAll)r*   )re   )r   r   )F)N)+r   r   r   r   rŠ   r9   r    r4   r8   r:   r<   rN   rQ   rS   r\   r]   rc   rf   rh   rj   ro   rq   rr   rs   rt   r{   r€   r�   r~   rx   r“   r”   r•   r�   rA   r˜   rœ   r�   rš   r¡   r¤   r¦   r§   r   r   r   r   r(   c   sR    
		








r(   )r(   ÚDEFAULT_PORTr   r   r   N)r   Úcollectionsr   Útwisted.internet.deferr   r   r   Útwisted.protocols.basicr   Útwisted.protocols.policiesr   Útwisted.pythonr   Útwisted.python.compatr	   r
   r¨   Ú	Exceptionr   r   r   r   r(   Ú__all__r   r   r   r   Ú<module>   s$   )    x