B
    @\')                 @   s   d Z ddlmZmZmZmZ ddlZeeZ	ddl
Z
ddlmZmZ ddlmZ ddlmZ d	Zd
d Zdd ZG dd deZdS )z( Provides the ``ServerSession`` class.

    )absolute_importdivisionprint_functionunicode_literalsN)genlocks   )yield_for_all_futures   )_DocumentCallbackGroup)current_timeServerSessionc                s   t j fdd}|S )zDecorator that adds the necessary locking and post-processing
       to manipulate the session's document. Expects to decorate a
       method on ServerSession and transforms it into a coroutine
       if it wasn't already.
    c          	   ?   s   | j rtd td |   z|| j V \ | jd k	rDt	dg | _zt
 | f||V }W d | j}d | _X x|D ]
}|V  qzW W d Q R X t|W d |   X d S )Nz6Ignoring locked callback on already-destroyed session.zUinternal class invariant violated: _pending_writes should be None if lock is not held)	destroyedlogdebugr   ZReturnblock_expiration_lockacquire_pending_writesRuntimeErrorr	   unblock_expiration)selfargskwargsresultZpending_writesp)func 3lib/python3.7/site-packages/bokeh/server/session.py_needs_document_lock_wrapper5   s"    



z:_needs_document_lock.<locals>._needs_document_lock_wrapper)r   	coroutine)r   r   r   )r   r   _needs_document_lock/   s    r!   c               C   s$   yt  d S    t   d S dS )zWReturn the time in milliseconds since the epoch as a floating
       point number.
    i  N)timeZ	monotonicr   r   r   r   r   X   s    r   c               @   sF  e Zd ZdZd?ddZedd Zedd Zed	d
 Zedd Z	e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edd Zedd  Zed!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zed+d, Zd-d. Zd/d0 Zed1d2 Zed3d4 Zed5d6 Z ed7d8 Z!ed9d: Z"ed;d< Z#ed=d> Z$dS )@r   z^ Hosts an application "instance" (an instantiated Document) for one or more connections.

    Nc             C   s   |d krt d|d kr t d|| _|| _|| _t | _t | _t	 | _
d | _| j|  t|| _d | _d| _d| _d| _| | jj}| j| d S )NzSessions must have an idzSessions must have a documentFr   )
ValueError_id	_documentZ_loopset_subscribed_connectionsr   _last_unsubscribe_timer   ZLockr   _current_patch_connectionZon_change_dispatch_tor   
_callbacksr   
_destroyed_expiration_requested_expiration_blocked_count_wrap_session_callbacksZsession_callbacksZadd_session_callbacks)r   Z
session_iddocumentZio_loopZwrapped_callbacksr   r   r   __init__h   s&    

zServerSession.__init__c             C   s   | j S )N)r%   )r   r   r   r   r/   ~   s    zServerSession.documentc             C   s   | j S )N)r$   )r   r   r   r   id   s    zServerSession.idc             C   s   | j S )N)r+   )r   r   r   r   r      s    zServerSession.destroyedc             C   s   | j S )N)r,   )r   r   r   r   expiration_requested   s    z"ServerSession.expiration_requestedc             C   s
   | j dkS )Nr   )r-   )r   r   r   r   expiration_blocked   s    z ServerSession.expiration_blockedc             C   s   | j S )N)r-   )r   r   r   r   expiration_blocked_count   s    z&ServerSession.expiration_blocked_countc             C   s(   d| _ | j|  | `| j  | `d S )NT)r+   r%   destroyr*   Zremove_all_callbacks)r   r   r   r   r5      s
    
zServerSession.destroyc             C   s
   d| _ dS )zK Used in test suite for now. Forces immediate expiration if no connections.TN)r,   )r   r   r   r   request_expiration   s    z ServerSession.request_expirationc             C   s   |  j d7  _ d S )Nr
   )r-   )r   r   r   r   r      s    zServerSession.block_expirationc             C   s$   | j dkrtd|  j d8  _ d S )Nr   z0mismatched block_expiration / unblock_expirationr
   )r-   r   )r   r   r   r   r      s    
z ServerSession.unblock_expirationc             C   s   | j | dS )zgThis should only be called by ``ServerConnection.subscribe_session`` or our book-keeping will be brokenN)r'   add)r   
connectionr   r   r   	subscribe   s    zServerSession.subscribec             C   s   | j | t | _dS )ziThis should only be called by ``ServerConnection.unsubscribe_session`` or our book-keeping will be brokenN)r'   discardr   r(   )r   r8   r   r   r   unsubscribe   s    zServerSession.unsubscribec             C   s
   t | jS )N)lenr'   )r   r   r   r   connection_count   s    zServerSession.connection_countc             C   s   t  | j S )N)r   r(   )r   r   r   r   #milliseconds_since_last_unsubscribe   s    z1ServerSession.milliseconds_since_last_unsubscribec             O   s
   |||S )zH Asynchronously locks the document and runs the function with it locked.r   )r   r   r   r   r   r   r   with_document_locked   s    z"ServerSession.with_document_lockedc                s"   t  ddr S  fdd}|S )NZnolockFc                 s   j  f| |S )N)r?   )r   r   )callbackr   r   r   wrapped_callback   s    z?ServerSession._wrap_document_callback.<locals>.wrapped_callback)getattr)r   r@   rA   r   )r@   r   r   _wrap_document_callback   s    z%ServerSession._wrap_document_callbackc             C   s   |  |j}||S )N)rC   r@   Z_copy_with_changed_callback)r   r@   wrappedr   r   r   _wrap_session_callback   s    z$ServerSession._wrap_session_callbackc             C   s&   g }x|D ]}| | | q
W |S )N)appendrE   )r   	callbacksrD   cbr   r   r   r.      s    
z%ServerSession._wrap_session_callbacksc             C   s^   |j | k}| jd krtdx<| jD ]2}|rD|| jkrDtd| q$| j|| q$W d S )Nzv_pending_writes should be non-None when we have a document lock, and we should have the lock when the document changeszDNot sending notification back to client %r for a change it requested)	setterr   r   r'   r)   r   ZtracerF   Zsend_patch_document)r   eventZmay_suppressr8   r   r   r   _document_patched   s    

zServerSession._document_patchedc             C   s&   t d| j |jd|jd | jS )Nz&Sending pull-doc-reply from session %rzPULL-DOC-REPLYZmsgid)r   r   r1   ZprotocolZcreateheaderr/   )r   messager8   r   r   r   _handle_pull   s    zServerSession._handle_pullc             C   s   |  |j}| j| d S )N)rE   r@   r*   Zadd_session_callback)r   rJ   rD   r   r   r   _session_callback_added   s    z%ServerSession._session_callback_addedc             C   s   | j |j d S )N)r*   Zremove_session_callbackr@   )r   rJ   r   r   r   _session_callback_removed   s    z'ServerSession._session_callback_removedc             C   s   |j ||S )z? Handle a PULL-DOC, return a Future with work to be scheduled. )sessionrN   )clsrM   r8   r   r   r   pull   s    zServerSession.pullc             C   s$   t d| j || j ||S )Nzpushing doc to session %r)r   r   r1   Zpush_to_documentr/   ok)r   rM   r8   r   r   r   _handle_push   s    zServerSession._handle_pushc             C   s   |j ||S )z? Handle a PUSH-DOC, return a Future with work to be scheduled. )rQ   rU   )rR   rM   r8   r   r   r   push   s    zServerSession.pushc             C   s,   || _ z|| j|  W d d | _ X ||S )N)r)   Zapply_to_documentr/   rT   )r   rM   r8   r   r   r   _handle_patch   s
    zServerSession._handle_patchc             C   s   | | j ||S )N)Znotify_eventr/   rT   )r   rM   r8   r   r   r   _handle_event  s    zServerSession._handle_eventc             C   s   |j ||S )N)rQ   rX   )rR   rM   r8   r   r   r   rJ     s    zServerSession.eventc             C   s   |j ||S )z@ Handle a PATCH-DOC, return a Future with work to be scheduled. )rQ   rW   )rR   rM   r8   r   r   r   patch  s    zServerSession.patch)N)%__name__
__module____qualname____doc__r0   propertyr/   r1   r   r2   r3   r4   r5   r6   r   r   r9   r;   r=   r>   r!   r?   rC   rE   r.   rK   rN   rO   rP   classmethodrS   rU   rV   rW   rX   rJ   rY   r   r   r   r   r   c   s>   
	
r   )r]   Z
__future__r   r   r   r   ZloggingZ	getLoggerrZ   r   r"   Ztornador   r   Zutil.tornador	   rG   r   __all__r!   r   objectr   r   r   r   r   <module>	   s   
)