U
    QV‚gM3  ã                   @   s¾   d dl Z d dlZd dlZd dl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 ddlmZmZ G d	d
„ d
ƒZG dd„ dƒZG dd„ deƒZefdd„Zeƒ ZdS )é    N)Údeepcopy)Úsettings)Úsetting_changed)Úimport_string)ÚDEFAULT_CHANNEL_LAYERé   )ÚChannelFullÚInvalidChannelLayerErrorc                   @   s\   e Zd ZdZdd„ Zdd„ Zedd„ ƒZdd	„ Zd
d„ Z	dd„ Z
dd„ Zdd„ Zdd„ ZdS )ÚChannelLayerManagerzR
    Takes a settings dictionary of backends and initialises them on request.
    c                 C   s   i | _ t | j¡ d S ©N)Úbackendsr   ÚconnectÚ_reset_backends©Úself© r   ú3/tmp/pip-unpacked-wheel-lkk2pq7o/channels/layers.pyÚ__init__   s    zChannelLayerManager.__init__c                 K   s   |dkri | _ dS )zX
        Removes cached channel layers when the CHANNEL_LAYERS setting changes.
        ÚCHANNEL_LAYERSN)r   )r   ZsettingÚkwargsr   r   r   r      s    z#ChannelLayerManager._reset_backendsc                 C   s   t tdi ƒS )Nr   )Úgetattrr   r   r   r   r   Úconfigs"   s    zChannelLayerManager.configsc                 C   s   | j |  di ¡}|  ||¡S )z,
        Instantiate channel layer.
        ZCONFIG)r   ÚgetÚ_make_backend©r   ÚnameÚconfigr   r   r   Úmake_backend'   s    z ChannelLayerManager.make_backendc                 C   s@   z| j | d }W n  tk
r2   td| ƒ‚Y nX |  ||¡S )zB
        Instantiate channel layer using its test config.
        ZTEST_CONFIGzNo TEST_CONFIG specified for %s)r   ÚKeyErrorr	   r   r   r   r   r   Úmake_test_backend.   s
    z%ChannelLayerManager.make_test_backendc                 C   sˆ   d| j | krtd| ƒ‚zt| j | d ƒ}W nL tk
rP   td| ƒ‚Y n. tk
r|   td| j | d |f ƒ‚Y nX |f |ŽS )NZROUTINGzBROUTING key found for %s - this is no longer needed in Channels 2.ZBACKENDzNo BACKEND specified for %sz)Cannot import BACKEND %r specified for %s)r   r	   r   r   ÚImportError)r   r   r   Zbackend_classr   r   r   r   8   s"    ÿÿÿÿ
z!ChannelLayerManager._make_backendc                 C   s$   || j kr|  |¡| j |< | j | S r   )r   r   ©r   Úkeyr   r   r   Ú__getitem__L   s    
zChannelLayerManager.__getitem__c                 C   s
   || j kS r   )r   r!   r   r   r   Ú__contains__Q   s    z ChannelLayerManager.__contains__c                 C   s   | j  |d¡}|| j |< |S )z»
        Sets an alias to point to a new ChannelLayerWrapper instance, and
        returns the old one that it replaced. Useful for swapping out the
        backend during tests.
        N)r   r   )r   r"   ZlayerÚoldr   r   r   ÚsetT   s    
zChannelLayerManager.setN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   Úpropertyr   r   r   r   r#   r$   r&   r   r   r   r   r
      s   

r
   c                   @   s¼   e Zd ZdZdZd*dd„Zdd„ Zd	d
„ Zdd„ Ze	 
d¡Ze	 
d¡Zdd e¡ d d Zd+dd„Zd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S )-ÚBaseChannelLayerzf
    Base channel layer class that others can inherit from, with useful
    common functionality.
    éd   é<   Nc                 C   s   || _ || _|pi | _d S r   ©ÚexpiryÚcapacityÚchannel_capacity)r   r0   r1   r2   r   r   r   r   g   s    zBaseChannelLayer.__init__c                 C   sN   g }|  ¡ D ]<\}}t|dƒr.| ||f¡ q| t t |¡¡|f¡ q|S )z 
        Takes an input channel_capacity dict and returns the compiled list
        of regexes that get_capacity will look for as self.channel_capacity
        Úmatch)ÚitemsÚhasattrÚappendÚreÚcompileÚfnmatchÚ	translate)r   r2   ÚresultÚpatternÚvaluer   r   r   Úcompile_capacitiesl   s    
z#BaseChannelLayer.compile_capacitiesc                 C   s(   | j D ]\}}| |¡r|  S q| jS )a  
        Gets the correct capacity for the given channel; either the default,
        or a matching result from channel_capacity. Returns the first matching
        result; if you want to control the order of matches, use an ordered dict
        as input.
        )r2   r3   r1   )r   Úchannelr<   r1   r   r   r   Úget_capacity{   s    

zBaseChannelLayer.get_capacityc                 C   s    t |tƒrt|ƒ| jk rdS dS )NTF)Ú
isinstanceÚstrÚlenÚMAX_NAME_LENGTH©r   r   r   r   r   Úmatch_type_and_length‡   s    z&BaseChannelLayer.match_type_and_lengthz!^[a-zA-Z\d\-_.]+(\![\d\w\-_.]*)?$z^[a-zA-Z\d\-_.]+$z'{} name must be a valid unicode string zwith length < {} zGcontaining only ASCII alphanumerics, hyphens, underscores, or periods, znot {}Fc                 C   sR   |   |¡r<t| j |¡ƒr<d|kr8| d¡s8|r8tdƒ‚dS t| j d|¡ƒ‚d S )Nú!z5Specific channel names in receive() must end at the !TZChannel)rF   ÚboolÚchannel_name_regexr3   ÚendswithÚ	TypeErrorÚinvalid_name_errorÚformat)r   r   Úreceiver   r   r   Úvalid_channel_name—   s    
ÿz#BaseChannelLayer.valid_channel_namec                 C   s4   |   |¡rt| j |¡ƒrdS t| j d|¡ƒ‚d S )NTÚGroup)rF   rH   Úgroup_name_regexr3   rK   rL   rM   rE   r   r   r   Úvalid_group_name¢   s    
z!BaseChannelLayer.valid_group_namec                    sF   |rdnd}t |tƒ}|r|s&tdƒ‚t‡ ‡fdd„|D ƒƒsBt‚dS )NTFznames must be a non-empty listc                 3   s   | ]}ˆj |ˆ d �V  qdS ))rN   N)rO   )Ú.0r?   ©rN   r   r   r   Ú	<genexpr>­   s    z7BaseChannelLayer.valid_channel_names.<locals>.<genexpr>)rA   ÚlistÚAssertionErrorÚall)r   ÚnamesrN   Z_non_empty_listZ_names_typer   rT   r   Úvalid_channel_names¨   s    
ÿz$BaseChannelLayer.valid_channel_namesc                 C   s&   d|kr|d|  d¡d … S |S dS )zõ
        Given a channel name, returns the "non-local" part. If the channel name
        is a process-specific channel (contains !) this means the part up to
        and including the !; if it is anything else, this means the full name.
        rG   Nr   )ÚfindrE   r   r   r   Únon_local_name²   s    zBaseChannelLayer.non_local_namec                 Ã   s   t dƒ‚d S )Nz/send() should be implemented in a channel layer©ÚNotImplementedError)r   r?   Úmessager   r   r   Úsend½   s    zBaseChannelLayer.sendc                 Ã   s   t dƒ‚d S )Nz2receive() should be implemented in a channel layerr]   )r   r?   r   r   r   rN   À   s    zBaseChannelLayer.receivec                 Ã   s   t dƒ‚d S )Nz6new_channel() should be implemented in a channel layerr]   r   r   r   r   Únew_channelÃ   s    ÿzBaseChannelLayer.new_channelc                 Ã   s   t dƒ‚d S )Nz)flush() not implemented (flush extension)r]   r   r   r   r   ÚflushÈ   s    zBaseChannelLayer.flushc                 Ã   s   t dƒ‚d S )Nz.group_add() not implemented (groups extension)r]   ©r   Úgroupr?   r   r   r   Ú	group_addË   s    zBaseChannelLayer.group_addc                 Ã   s   t dƒ‚d S )Nz2group_discard() not implemented (groups extension)r]   rc   r   r   r   Úgroup_discardÎ   s    zBaseChannelLayer.group_discardc                 Ã   s   t dƒ‚d S )Nz/group_send() not implemented (groups extension)r]   )r   rd   r_   r   r   r   Ú
group_sendÑ   s    zBaseChannelLayer.group_send)r.   r-   N)F)F)r'   r(   r)   r*   rD   r   r>   r@   rF   r7   r8   rI   rQ   rM   rL   rO   rR   rZ   r\   r`   rN   ra   rb   re   rf   rg   r   r   r   r   r,   _   s6   


ÿþýÿ


r,   c                       s|   e Zd ZdZd‡ fdd„	Zdd	gZd
d„ Zd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‡  ZS )!ÚInMemoryChannelLayerz0
    In-memory channel layer implementation
    r.   é€Q r-   Nc                    s0   t ƒ jf |||dœ|—Ž i | _i | _|| _d S )Nr/   )Úsuperr   ÚchannelsÚgroupsÚgroup_expiry)r   r0   rm   r1   r2   r   ©Ú	__class__r   r   r   Ú   s    ýüzInMemoryChannelLayer.__init__rl   rb   c                 Ã   s’   t |tƒstdƒ‚|  |¡s$tdƒ‚d|ks0t‚| j |tj|  |¡d�¡}z | 	t
 
¡ | j t|ƒf¡ W n  tjjk
rŒ   t|ƒ‚Y nX dS )zF
        Send a message onto a (general or specific) channel.
        zmessage is not a dictúChannel name not validZ__asgi_channel__©ÚmaxsizeN)rA   ÚdictrW   rO   rk   Ú
setdefaultÚasyncioÚQueuer@   Ú
put_nowaitÚtimer0   r   ZqueuesZ	QueueFullr   )r   r?   r_   Úqueuer   r   r   r`   ð   s     ÿ zInMemoryChannelLayer.sendc              
   Ã   sf   |   |¡st‚|  ¡  | j |tj|  |¡d�¡}z| 
¡ I dH \}}W 5 | ¡ r`| j 	|d¡ X |S )zÊ
        Receive the first message that arrives on the channel.
        If more than one coroutine waits on the same channel, a random one
        of the waiting coroutines will get the result.
        rq   N)rO   rW   Ú_clean_expiredrk   rt   ru   rv   r@   ÚemptyÚpopr   )r   r?   ry   Ú_r_   r   r   r   rN     s     ÿzInMemoryChannelLayer.receiveú	specific.c                 Ã   s    d|d  dd„ tdƒD ƒ¡f S )zx
        Returns a new channel name that can be used by something in our
        process as a specific channel.
        z%s.inmemory!%sÚ c                 s   s   | ]}t  tj¡V  qd S r   )ÚrandomÚchoiceÚstringÚascii_letters)rS   Úir   r   r   rU   !  s     z3InMemoryChannelLayer.new_channel.<locals>.<genexpr>é   )ÚjoinÚrange)r   Úprefixr   r   r   ra     s    þz InMemoryChannelLayer.new_channelc                 C   s´   t | j ¡ ƒD ]P\}}| ¡ s|jd d t ¡ k r| ¡  |  |¡ | ¡ r| j |d¡ qqt	t ¡ ƒ| j
 }| j ¡ D ]2}t | ¡ ƒD ] \}}|rŒ||k rŒ| |d¡ qŒq|dS )z¢
        Goes through all messages and groups and removes those that are expired.
        Any channel with an expired message is removed from all groups.
        r   N)rV   rk   r4   r{   Ú_queuerx   Ú
get_nowaitÚ_remove_from_groupsr|   Úintrm   rl   Úvalues)r   r?   ry   Útimeoutrk   r   Ú	timestampr   r   r   rz   &  s    
z#InMemoryChannelLayer._clean_expiredc                 Ã   s   i | _ i | _d S r   )rk   rl   r   r   r   r   rb   B  s    zInMemoryChannelLayer.flushc                 Ã   s   d S r   r   r   r   r   r   ÚcloseF  s    zInMemoryChannelLayer.closec                 C   s    | j  ¡ D ]}| |d¡ q
dS )zW
        Removes a channel from all groups. Used when a message on it expires.
        N)rl   r�   r|   )r   r?   rk   r   r   r   r‹   J  s    z(InMemoryChannelLayer._remove_from_groupsc                 Ã   sH   |   |¡stdƒ‚|  |¡s$tdƒ‚| j |i ¡ t ¡ | j| |< dS )z3
        Adds the channel name to a group.
        zGroup name not validrp   N)rR   rW   rO   rl   rt   rx   rc   r   r   r   re   S  s    zInMemoryChannelLayer.group_addc                 Ã   sX   |   |¡stdƒ‚|  |¡s$tdƒ‚| j |d ¡}|rT| |d ¡ |sT| j |d ¡ d S )NzInvalid channel nameúInvalid group name)rO   rW   rR   rl   r   r|   )r   rd   r?   Zgroup_channelsr   r   r   rf   ^  s    z"InMemoryChannelLayer.group_discardc              	   Ã   sž   t |tƒstdƒ‚|  |¡s$tdƒ‚|  ¡  g }|| jkrf| j|  ¡ D ]}| t 	|  
||¡¡¡ qHt |¡D ](}z|I d H  W qp tk
r–   Y qpX qpd S )NzMessage is not a dictr‘   )rA   rs   rW   rR   rz   rl   Úkeysr6   ru   Zcreate_taskr`   Zas_completedr   )r   rd   r_   Úopsr?   Zsend_resultr   r   r   rg   k  s    
zInMemoryChannelLayer.group_send)r.   ri   r-   N)r~   )r'   r(   r)   r*   r   Ú
extensionsr`   rN   ra   rz   rb   r�   r‹   re   rf   rg   Ú__classcell__r   r   rn   r   rh   Õ   s"       û
	rh   c                 C   s&   z
t |  W S  tk
r    Y dS X dS )zL
    Returns a channel layer by alias, or None if it is not configured.
    N)Úchannel_layersr   )Úaliasr   r   r   Úget_channel_layer~  s    
r˜   )ru   r9   r€   r7   r‚   rx   Úcopyr   Zdjango.confr   Zdjango.core.signalsr   Zdjango.utils.module_loadingr   rk   r   Ú
exceptionsr   r	   r
   r,   rh   r˜   r–   r   r   r   r   Ú<module>   s"   Mv *