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
mZ ddlmZ ddlmZ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eZdS )zA Provides the Application, Server, and Session context classes.

    )absolute_importdivisionprint_functionunicode_literalsN)gen   )ServerSession   )ServerContextSessionContext)Document)ProtocolError)_CallbackGroupyield_for_all_futures)ApplicationContextBokehServerContextBokehSessionContextc               @   sX   e 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 )r   c             C   s   || _ t| j j| _d S )N)application_contextr   io_loop
_callbacks)selfr    r   4lib/python3.7/site-packages/bokeh/server/contexts.py__init__;   s    zBokehServerContext.__init__c             C   s   | j   d S )N)r   Zremove_all_callbacks)r   r   r   r   _remove_all_callbacks?   s    z(BokehServerContext._remove_all_callbacksc             C   s$   g }x| j jD ]}|| qW |S )N)r   sessionsappend)r   resultsessionr   r   r   r   B   s    zBokehServerContext.sessionsc             C   s   | j |S )N)r   add_next_tick_callback)r   callbackr   r   r   r   I   s    z)BokehServerContext.add_next_tick_callbackc             C   s   | j | d S )N)r   remove_next_tick_callback)r   callback_idr   r   r   r!   L   s    z,BokehServerContext.remove_next_tick_callbackc             C   s   | j ||S )N)r   add_timeout_callback)r   r    Ztimeout_millisecondsr   r   r   r#   O   s    z'BokehServerContext.add_timeout_callbackc             C   s   | j | d S )N)r   remove_timeout_callback)r   r"   r   r   r   r$   R   s    z*BokehServerContext.remove_timeout_callbackc             C   s   | j ||S )N)r   add_periodic_callback)r   r    Zperiod_millisecondsr   r   r   r%   U   s    z(BokehServerContext.add_periodic_callbackc             C   s   | j | d S )N)r   remove_periodic_callback)r   r"   r   r   r   r&   X   s    z+BokehServerContext.remove_periodic_callbackN)__name__
__module____qualname__r   r   propertyr   r   r!   r#   r$   r%   r&   r   r   r   r   r   :   s   r   c                   sV   e Zd Z fddZdd Zejdd Zedd Z	ed	d
 Z
edd Z  ZS )r   c                s(   || _ d | _tt| || d | _d S )N)	_document_sessionsuperr   r   _request)r   
session_idserver_contextdocument)	__class__r   r   r   \   s
    zBokehSessionContext.__init__c             C   s
   || _ d S )N)r,   )r   r   r   r   r   _set_sessiond   s    z BokehSessionContext._set_sessionc             c   s0   | j d krt|| jV  n| j || j d S )N)r,   r   r+   with_document_locked)r   funcr   r   r   with_locked_documentg   s    
z(BokehSessionContext.with_locked_documentc             C   s   | j d krdS | j jS d S )NF)r,   	destroyed)r   r   r   r   r7   p   s    
zBokehSessionContext.destroyedc             C   s   | j S )N)r.   )r   r   r   r   requestx   s    zBokehSessionContext.requestc             C   s   | j S )N)r,   )r   r   r   r   r   |   s    zBokehSessionContext.session)r'   r(   r)   r   r3   r   	coroutiner6   r*   r7   r8   r   __classcell__r   r   )r2   r   r   [   s   	r   c               @   s   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
dd Zdd ZejdddZdd Zejdd Zejdd ZdS )r   z Server-side holder for ``bokeh.application.Application`` plus any associated data.
        This holds data that's global to all sessions, while ``ServerSession`` holds
        data specific to an "instance" of the application.
    Nc             C   s4   || _ || _t | _t | _t | _d | _|| _d S )N)_application_loopdict	_sessions_pending_sessions_session_contexts_server_context_url)r   applicationr   urlr   r   r   r      s    zApplicationContext.__init__c             C   s   | j S )N)r<   )r   r   r   r   r      s    zApplicationContext.io_loopc             C   s   | j S )N)r;   )r   r   r   r   rC      s    zApplicationContext.applicationc             C   s   | j S )N)rB   )r   r   r   r   rD      s    zApplicationContext.urlc             C   s   | j d krt| | _ | j S )N)rA   r   )r   r   r   r   r0      s    

z!ApplicationContext.server_contextc             C   s
   | j  S )N)r>   values)r   r   r   r   r      s    zApplicationContext.sessionsc          
   C   s`   y(| j | j}t|tjr&td W n2 tk
rZ } ztjd|dd W d d }~X Y nX d S )Nzqon_server_loaded returned a Future; this doesn't make sense because we run this hook before starting the IO loop.zError in server loaded hook %rT)exc_info)	r;   Zon_server_loadedr0   
isinstancer   Futurelogerror	Exception)r   r   er   r   r   run_load_hook   s    z ApplicationContext.run_load_hookc          
   C   sj   y(| j | j}t|tjr&td W n2 tk
rZ } ztjd|dd W d d }~X Y nX | j	  d S )Nzon_server_unloaded returned a Future; this doesn't make sense because we stop the IO loop right away after calling on_server_unloaded.z Error in server unloaded hook %rT)rF   )
r;   Zon_server_unloadedr0   rG   r   rH   rI   rJ   rK   r   )r   r   rL   r   r   r   run_unload_hook   s    "z"ApplicationContext.run_unload_hookc          
   c   s&  t |dkrtd|| jkr|| jkrt  }| j|< t }t|| j|}t	||_
||_yt| j|V  W n2 tk
r } ztjd|dd W d d }~X Y nX | j| t||| jd}| j|= || j|< || || j|< || || jkr| j| V }n
| j| }t|d S )Nr   zSession ID must not be emptyz'Failed to run session creation hooks %rT)rF   )r   )lenr   r>   r?   r   rH   r   r   r0   _RequestProxyr.   Z_session_contextr   r;   Zon_session_createdrK   rI   rJ   Zinitialize_documentr   r<   r3   r@   Z
set_resultReturn)r   r/   r8   Zfuturedocsession_contextrL   r   r   r   r   create_session_if_needed   s4    


"




z+ApplicationContext.create_session_if_neededc             C   s(   || j kr| j | }|S td| d S )NzNo such session )r>   r   )r   r/   r   r   r   r   get_session   s    

zApplicationContext.get_sessionc          
   #   s   j dkrtdtdjj  jj } fdd}|V  |jry j	
|}t|V  W n2 tk
r } ztjd|dd W d d }~X Y nX td d S )	Nr   z8Should not be discarding a session with open connectionsz5Discarding session %r last in use %r milliseconds agoc                  sP   r>j dkr>   jj=  jj= tdj ntdj d S )Nr   z%Session %r was successfully discardedz9Session %r was scheduled to discard but came back to life)Zexpiration_blocked_countZdestroyr>   idr@   rI   ZtraceZwarningr   )r   r   should_discardr   r   
do_discard   s    

z7ApplicationContext._discard_session.<locals>.do_discardz&Failed to run session destroy hooks %rT)rF   )connection_countRuntimeErrorrI   debugrV   #milliseconds_since_last_unsubscriber@   r4   r7   r;   Zon_session_destroyedr   rK   rJ   r   rQ   )r   r   rW   rS   rX   r   rL   r   )r   r   rW   r   _discard_session   s    
"z#ApplicationContext._discard_sessionc             #   s    fdd}g }x*| j  D ]}||r|js|| qW t|dkrZtdt|  x(|D ] }||r`|js`| ||V  q`W t	d d S )Nc                s   | j dko| j kp| jS )Nr   )rY   r\   Zexpiration_requested)r   )"unused_session_linger_millisecondsr   r   should_discard_ignoring_block  s    

zKApplicationContext._cleanup_sessions.<locals>.should_discard_ignoring_blockr   z!Scheduling %s sessions to discard)
r>   rE   Zexpiration_blockedr   rO   rI   r[   r]   r   rQ   )r   r^   r_   Z
to_discardr   r   )r^   r   _cleanup_sessions  s    
z$ApplicationContext._cleanup_sessions)NN)N)r'   r(   r)   __doc__r   r*   r   rC   rD   r0   r   rM   rN   r   r9   rT   rU   r]   r`   r   r   r   r   r      s   
		0$r   c               @   s    e Zd Zdd Zedd ZdS )rP   c             C   s0   t |j}d|kr|d= d|kr&|d= || _d S )Nzbokeh-protocol-versionzbokeh-session-id)r=   	arguments_args)r   r8   Z	args_copyr   r   r   r   0  s    
  z_RequestProxy.__init__c             C   s   | j S )N)rc   )r   r   r   r   rb   5  s    z_RequestProxy.argumentsN)r'   r(   r)   r   r*   rb   r   r   r   r   rP   /  s   rP   )ra   Z
__future__r   r   r   r   ZloggingZ	getLoggerr'   rI   Ztornador   r   r   Zapplication.applicationr
   r   r1   r   Zprotocol.exceptionsr   Zutil.tornador   r   __all__r   r   objectr   rP   r   r   r   r   <module>	   s   
	!& /