B
    0`R]                 @   s   d Z ddlmZ ddlm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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)LineReceiver)TimeoutMixin)DeferredfailTimeoutError)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   I/home/dcms/DCMS/lib/python3.7/site-packages/twisted/protocols/memcache.pyr   )   s   r   c               @   s   e Zd ZdZdS )ClientErrorz1
    Error caused by an invalid client call.
    N)r   r   r   r   r   r   r   r   r   /   s   r   c               @   s   e Zd ZdZdS )ServerErrorz*
    Problem happening on the server.
    N)r   r   r   r   r   r   r   r   r   5   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   s4   || _ t | _x | D ]\}}t| || qW 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__H   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   successW   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$   x| j r| j  }|| qW 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   r2      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   r4      s    zMemCacheProtocol.sendLinec             C   s   |    | j| |  jt|7  _| j| jd krd| 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    )r   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.
        FN)r%   r+   r    )r   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.
        s   getc             S   s    i | ]\}}|d d d |qS )Nr6   r   ).0keyrB   r   r   r   
<dictcomp>   s    z,MemCacheProtocol.cmd_END.<locals>.<dictcomp>s   getss   statsz%Unexpected END response to {} commandN)r%   r+   r   r<   r=   r   r    rC   r   rD   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.
        FN)r%   r+   r    )r   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rt	dt||_||_|   dS )z:
        Prepare the reading a value after a get.
        r   s   getr7   zUnexpected commands answer.N)r%   r   splitintr&   r'   r(   r<   keysrK   r>   r=   rI   rC   rD   Z
setRawMode)r   r5   r-   rI   rC   lengthrD   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%   rO   r=   )r   r5   r-   rI   rB   r   r   r   cmd_STAT
  s    
zMemCacheProtocol.cmd_STATc             C   s   | j  | dS )z%
        Read version token.
        N)r%   r+   r    )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   rX   r%   r+   r   r   )r   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)rZ   r   rX   r%   r+   r   r   )r   r[   r-   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.
        TN)r%   r+   r    )r   r   r   r   cmd_DELETED2  s    zMemCacheProtocol.cmd_DELETEDc             C   s   | j  d dS )z6
        The last command has been completed.
        TN)r%   r+   r    )r   r   r   r   cmd_OK8  s    zMemCacheProtocol.cmd_OKc             C   s   | j  d dS )z5
        A C{checkAndSet} update has failed.
        FN)r%   r+   r    )r   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.
        rT   rU   r   Zcmd_N   _)
r8   rO   getattrr	   replacer%   r+   rP   r    r3   )r   r5   tokenr-   argsrB   r   r   r   lineReceivedD  s"    

zMemCacheProtocol.lineReceivedrU   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   rI   rB   r   r   r   	incrementa  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   decr)rg   )r   rI   rB   r   r   r   	decrementr  s    zMemCacheProtocol.decrementc             C   s   | j rttdS t|ts2ttdt|S t|| j	krLttdS d
||dt|f g}| | t||d}| j| |jS )z1
        Internal wrapper for incr/decr.
        znot connectedz)Invalid type for key: {}, expecting byteszKey too longrT   s   %d)rI   )r1   r   rK   
isinstancebytesr   rL   typer:   MAX_KEY_LENGTHr;   rP   r4   r   r%   r9   r   )r   r-   rI   rB   fullcmdcmdObjr   r   r   rg     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   replacer7   )_set)r   rI   rB   rC   
expireTimer   r   r   rc     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   addr7   )rp   )r   rI   rB   rC   rq   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   setr7   )rp   )r   rI   rB   rC   rq   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   cas)rp   )r   rI   rB   rD   rC   rq   r   r   r   checkAndSet  s    zMemCacheProtocol.checkAndSetc       
   	   C   s   | j rttdS t|ts2ttdt|S t|| j	krLttdS t|tslttdt|S |rxd| }t|}d
||td|||f g| }| | | | t||||d}	| j|	 |	jS )z6
        Internal wrapper for setting values.
        znot connectedz)Invalid type for key: {}, expecting byteszKey too longz+Invalid type for value: {}, expecting bytesrT   z%d %d %d)rI   rC   rR   )r1   r   rK   rj   rk   r   rL   rl   r:   rm   r;   r
   r4   r   r%   r9   r   )
r   r-   rI   rB   rC   rq   rD   rR   rn   ro   r   r   r   rp     s.    



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   r7   )rp   )r   rI   rB   r   r   r   r9     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   r7   )rp   )r   rI   rB   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   rI   withIdentifierr   r   r   get@  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
        T)rv   )r   rQ   rw   r   r   r   getMultipleX  s    zMemCacheProtocol.getMultiplec       	      C   s   t |}| jrttdS xF|D ]>}t|tsDttdt|S t	|| j
kr ttdS q W |rld}nd}d|g| }| | |rd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}.
        znot connectedz)Invalid type for key: {}, expecting byteszKey too longs   getss   getrT   c             S   s   i | ]
}d |qS ))r   r7   Nr   )rH   rI   r   r   r   rJ     s    z)MemCacheProtocol._get.<locals>.<dictcomp>T)rQ   r=   r<   r   Nr7   F)rI   r   rC   rD   r<   )listr1   r   rK   rj   rk   r   rL   rl   r:   rm   r;   r4   r   r%   r9   r   )	r   rQ   rw   r<   rI   r-   rn   r=   ro   r   r   r   rv   r  s,    


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 s   statsznot connected)r=   )r1   r   rK   r4   r   r%   r9   r   )r   argr-   ro   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}
        znot connecteds   version)r1   r   rK   r4   r   r%   r9   r   )r   ro   r   r   r   version  s    
zMemCacheProtocol.versionc             C   s^   | j rttdS t|ts2ttdt|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}
        znot connectedz)Invalid type for key: {}, expecting bytess   delete s   delete)rI   )r1   r   rK   rj   rk   r   rL   rl   r4   r   r%   r9   r   )r   rI   ro   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}
        znot connecteds	   flush_all)r1   r   rK   r4   r   r%   r9   r   )r   ro   r   r   r   flushAll  s    
zMemCacheProtocol.flushAll)r$   )rU   )rU   )r   r   )r   r   )r   r   )r   r   )F)F)N)+r   r   r   r   rm   r1   r   r.   r0   r2   r4   rE   rF   rG   rM   rN   rS   rV   rW   rY   r\   r]   r^   r_   r`   rf   rh   ri   rg   rc   rr   rs   rt   rp   r9   ru   rx   ry   rv   r|   r}   r~   r   r   r   r   r   r"   d   sP   
		





#

 
r"   DEFAULT_PORTN)r   collectionsr   Ztwisted.protocols.basicr   Ztwisted.protocols.policiesr   Ztwisted.internet.deferr   r   r   Ztwisted.pythonr   Ztwisted.python.compatr	   r
   r   	Exceptionr   r   r   r   r"   __all__r   r   r   r   <module>   s,   )     