ó
mÜJ]c           @` s6  d  Z  d d l m Z m Z m Z m Z d d l Z e j e ƒ Z	 d d l
 Z
 d d l m Z d d l m Z 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 m Z m Z d	 d l m Z d	 d l m Z d d l  m! Z! d d l" m# Z# d f Z$ d e f d „  ƒ  YZ% e& Z' d S(   uA    Provide a web socket handler for the Bokeh Server application.

i    (   t   absolute_importt   divisiont   print_functiont   unicode_literalsN(   t   urlparse(   t   gent   locks(   t   StreamClosedErrort   WebSocketHandlert   WebSocketClosedErrori   (   t   ProtocolHandleri   (   t   Protocol(   t   MessageErrort   ProtocolErrort   ValidationError(   t   Message(   t   Receiver(   t   check_session_id_signature(   t   settingsu	   WSHandlert	   WSHandlerc           B` sÚ   e  Z d  Z d „  Z d „  Z d „  Z d „  Z e j d „  ƒ Z	 e j d „  ƒ Z
 d „  Z e j d „  ƒ Z e j e e d	 „ ƒ Z d
 „  Z e j d „  ƒ Z e j d „  ƒ Z e j d „  ƒ Z d „  Z d „  Z RS(   uI    Implements a custom Tornado WebSocketHandler for the Bokeh Server.

    c         O` s`   d  |  _ d  |  _ d  |  _ | d |  _ d |  _ t j ƒ  |  _ t	 t
 |  ƒ j | | | Ž d  S(   Nu   application_contextiÿÿÿÿ(   t   Nonet   receivert   handlert
   connectiont   application_contextt   latest_pongR   t   Lockt
   write_lockt   superR   t   __init__(   t   selft   tornado_appt   argst   kw(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyR   ?   s    				c         C` s   d  S(   N(    (   R   R   t   bokeh_websocket_path(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt
   initializeL   s    c         C` s’   d d l  m } t | ƒ } | j j ƒ  } |  j j } t j ƒ  rX t	 t j ƒ  ƒ } n  | | | ƒ } | rq t
 St j d | | | | ƒ t Sd S(   uš   Implement a check_origin policy for Tornado to call.

        The supplied origin will be compared to the Bokeh server whitelist. If the
        origin is not allow, an error will be logged and ``False`` will be returned.

        Args:
            origin (str) :
                The URL of the connection origin

        Returns:
            bool, True if the connection is allowed, False otherwise

        i   (   t   check_whitelistu³   Refusing websocket connection from Origin '%s';                       use --allow-websocket-origin=%s or set BOKEH_ALLOW_WS_ORIGIN=%s to permit this; currently we allow origins %rN(   t   utilR$   R   t   netloct   lowert   applicationt   websocket_originsR   t   allowed_ws_origint   sett   Truet   logt   errort   False(   R   t   originR$   t   parsed_origint   origin_hostt   allowed_hostst   allowed(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   check_originO   s    c         C` sù   t  j d ƒ |  j d d d ƒ} | d k rG |  j ƒ  t d ƒ ‚ n  |  j d d d ƒ} | d k r |  j ƒ  t d ƒ ‚ n  t | d |  j j d |  j j	 ƒsÄ t  j
 d	 | ƒ t d
 ƒ ‚ n  d „  } |  j | | ƒ } |  j j j | | ƒ d S(   uR    Initialize a connection to a client.

        Returns:
            None

        u   WebSocket connection openedu   bokeh-protocol-versiont   defaultu#   No bokeh-protocol-version specifiedu   bokeh-session-idu   No bokeh-session-id specifiedt   signedt
   secret_keyu$   Session id had invalid signature: %ru   Invalid session IDc         S` s/   |  j  ƒ  } | d  k	 r+ t j d | ƒ n  d  S(   Nu"   Failed to fully open connection %r(   t	   exceptionR   R-   t   debug(   t   futuret   e(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   on_fully_opened‡   s    N(   R-   t   infot   get_argumentR   t   closeR   R   R(   t   sign_sessionsR8   R.   t   _async_opent   io_loopt
   add_future(   R   t   proto_versiont
   session_idR=   R;   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   openn   s"    

		c         c` s  y¢ |  j  j | |  j ƒ V|  j  j | ƒ } t | ƒ } t | ƒ |  _ t j d | ƒ t	 ƒ  |  _
 t j d | ƒ |  j j | |  |  j  | ƒ |  _ t j d ƒ Wn3 t k
 r× } t j d | ƒ |  j ƒ  | ‚ n X|  j j j d ƒ } |  j | ƒ Vt j d ƒ ‚ d S(   u‰   Perform the specific steps needed to open a connection to a Bokeh session

        Specifically, this method coordinates:

        * Getting a session for a session ID (creating a new one if needed)
        * Creating a protocol receiver and hander
        * Opening a new ServerConnection and sending it an ACK

        Args:
            session_id (str) :
                A session ID to for a session to connect to

                If no session exists with the given ID, a new session is made

            proto_version (str):
                The protocol version requested by the connecting client.

        Returns:
            None

        u   Receiver created for %ru   ProtocolHandler created for %ru   ServerConnection createdu/   Could not create new server session, reason: %su   ACKN(   R   t   create_session_if_neededt   requestt   get_sessionR   R   R   R-   R:   R
   R   R(   t   new_connectionR   R>   R   R.   R@   t   protocolt   createt   send_messageR   t   ReturnR   (   R   RF   RE   t   sessionRL   R<   t   msg(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRB   ’   s"    !

c         c` sò   y |  j  | ƒ V} Wn9 t k
 rO } t j d | | d t ƒ|  j d ƒ n XyS | r¢ t d k	 rx t j j	 | ƒ n  |  j
 | ƒ V} | r¢ |  j | ƒ Vq¢ n  Wn9 t k
 rÞ } t j d | | d t ƒ|  j d ƒ n Xt j d ƒ ‚ d S(   u   Process an individual wire protocol fragment.

        The websocket RFC specifies opcodes for distinguishing text frames
        from binary frames. Tornado passes us either a text or binary string
        depending on that opcode, we have to look at the type of the fragment
        to see what we got.

        Args:
            fragment (unicode or bytes) : wire fragment to process

        u/   Unhandled exception receiving a message: %r: %rt   exc_infou    server failed to parse a messageu.   Handler or its work threw an exception: %r: %ru!   server failed to handle a messageN(   t   _receivet	   ExceptionR-   R.   R,   t   _internal_errort   _message_test_portR   t   receivedt   appendt   _handlet	   _scheduleR   RO   (   R   t   fragmentt   messageR<   t   work(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt
   on_messageÁ   s     c         C` ss   y t  t j | d ƒ ƒ |  _ WnM t k
 rH t j d | d t ƒn' t k
 rn t j d | d t ƒn Xd  S(   Nu   utf-8u#   received invalid unicode in pong %rRR   u#   received invalid integer in pong %r(	   t   intt   codecst   decodeR   t   UnicodeDecodeErrorR-   t   traceR,   t
   ValueError(   R   t   data(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   on_pongè   s    c         c` sk   y1 t  d k	 r" t  j j | ƒ n  | j |  ƒ VWn$ t t f k
 rW t j d ƒ n Xt	 j
 d ƒ ‚ d S(   u‰    Send a Bokeh Server protocol message to the connected client.

        Args:
            message (Message) : a message to send

        u/   Failed sending message as connection was closedN(   RV   R   t   sentRX   t   sendR	   R   R-   t   warningR   RO   (   R   R\   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRN   ò   s    c         c` sX   | r: |  j  j ƒ  V t t |  ƒ j | | ƒ VWd QXn t t |  ƒ j | | ƒ Vd S(   uj    Override parent write_message with a version that acquires a
        write lock before writing.

        N(   R   t   acquireR   R   t   write_message(   R   R\   t   binaryt   locked(    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRk     s    #c         C` sB   t  j d |  j |  j ƒ |  j d k	 r> |  j j |  j ƒ n  d S(   u2    Clean up when the connection is closed.

        u/   WebSocket connection closed: code=%s, reason=%rN(   R-   R>   t
   close_codet   close_reasonR   R   R(   t   client_lost(   R   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   on_close  s    c         c` sk   y& |  j  j | ƒ V} t j | ƒ ‚ Wn> t t t f k
 rf } |  j t | ƒ ƒ t j d  ƒ ‚ n Xd  S(   N(
   R   t   consumeR   RO   R   R   R   t   _protocol_errort   strR   (   R   R[   R\   R<   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRS     s    c         c` sq   y, |  j  j | |  j ƒ V} t j | ƒ ‚ Wn> t t t f k
 rl } |  j t	 | ƒ ƒ t j d  ƒ ‚ n Xd  S(   N(   R   t   handleR   R   RO   R   R   R   RU   Rt   R   (   R   R\   R]   R<   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRY   !  s    c         c` sJ   t  | t ƒ r  |  j | ƒ Vn |  j d t | ƒ ƒ t j d  ƒ ‚ d  S(   Nu   expected a Message not (   t
   isinstanceR   RN   RU   t   reprR   RO   R   (   R   R]   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRZ   +  s    c         C` s$   t  j d | ƒ |  j d | ƒ d  S(   Nu3   Bokeh Server internal error: %s, closing connectioni'  (   R-   R.   R@   (   R   R\   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRU   4  s    c         C` s$   t  j d | ƒ |  j d | ƒ d  S(   Nu3   Bokeh Server protocol error: %s, closing connectioni'  (   R-   R.   R@   (   R   R\   (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyRs   8  s    (   t   __name__t
   __module__t   __doc__R   R#   R5   RG   R   t	   coroutineRB   R^   Rf   RN   R/   R,   Rk   Rq   RS   RY   RZ   RU   Rs   (    (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyR   ;   s"   				$/'	
	

		((   Rz   t
   __future__R    R   R   R   t   loggingt	   getLoggerRx   R-   R`   t   six.moves.urllib.parseR   t   tornadoR   R   t   tornado.websocketR   R   R	   t   protocol_handlerR
   RL   R   t   protocol.exceptionsR   R   R   t   protocol.messageR   t   protocol.receiverR   t   bokeh.util.session_idR   t   bokeh.settingsR   t   __all__R   R   RV   (    (    (    s4   lib/python2.7/site-packages/bokeh/server/views/ws.pyt   <module>	   s$   "	ÿ 