a
    ën§af4  ã                   @  s0  U d Z ddlmZ ddlZe e¡ZddlZddlZ	ddl
mZmZmZmZmZ ddlmZ ddlmZmZ ddlmZ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"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- dZ.G dd„ de-eƒZ/e)G dd„ dƒƒZ0dZ1de2d< dS )zA Provide a web socket handler for the Bokeh Server application.

é    )ÚannotationsN)ÚAnyÚDictÚListÚUnionÚcast)Úurlparse)ÚlocksÚweb)ÚWebSocketClosedErrorÚWebSocketHandler)Úsettings)Úcheck_token_signatureÚget_session_idÚget_token_payloadé   )ÚProtocol)ÚMessageErrorÚProtocolErrorÚValidationError)ÚMessage)ÚReceiver)Ú	dataclassé   )ÚProtocolHandleré   )Ú	AuthMixin)Ú	WSHandlerc                      s(  e Zd ZdZddœ‡ fdd„Zdd„ Zdd	d
œdd„Zejddœdd„ƒZ	dddœdd„Z
ddœdd„Zdddœdd„Zdddœdd„Zdddœd d!„Zd"dd#œd$d%„Zd<d(d	d	dd)œ‡ fd*d+„Zddœd,d-„Zdd.dœd/d0„Zd"d1d#œd2d3„Zd4dd5œd6d7„Zddd#œd8d9„Zddd#œd:d;„Z‡  ZS )=r   zI Implements a custom Tornado WebSocketHandler for the Bokeh Server.

    ÚNone)Úreturnc                   sl   d | _ d | _d | _|d | _d| _t ¡ | _d | _| 	dd ¡| _
| 	dd ¡| _tƒ j|g|¢R i |¤Ž d S )NÚapplication_contextéÿÿÿÿÚcompression_levelÚ	mem_level)ÚreceiverÚhandlerÚ
connectionr    Úlatest_pongr	   ZLockÚ
write_lockÚ_tokenÚpopÚ_compression_levelÚ
_mem_levelÚsuperÚ__init__)ÚselfZtornado_appÚargsÚkw©Ú	__class__© ú4lib/python3.9/site-packages/bokeh/server/views/ws.pyr.   H   s    

zWSHandler.__init__c                 C  s   d S ©Nr4   )r/   r    Zbokeh_websocket_pathr4   r4   r5   Ú
initializeZ   s    zWSHandler.initializeÚstrÚbool)Úoriginr   c                 C  sf   ddl m} t|ƒ}|j ¡ }| jj}t ¡ r:t	t ¡ ƒ}|||ƒ}|rLdS t
 d||||¡ dS dS )aš   Implement a check_origin policy for Tornado to call.

        The supplied origin will be compared to the Bokeh server allowlist. 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

        r   )Úcheck_allowlistTz³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 %rFN)Úutilr;   r   ZnetlocÚlowerÚapplicationZwebsocket_originsr   Zallowed_ws_originÚsetÚlogÚerror)r/   r:   r;   Zparsed_originZorigin_hostZallowed_hostsZallowedr4   r4   r5   Úcheck_origin]   s    

þzWSHandler.check_originc              
   C  s  t  d¡ | j}| jdkr,|  ¡  tdƒ‚n|du rD|  ¡  tdƒ‚t tj	 
¡  ¡ ¡}t|ƒ}d|vrz|  ¡  tdƒ‚nP||d kr˜|  ¡  tdƒ‚n2t|| jj| jjd	sÊt|ƒ}t  d
|¡ tdƒ‚z| jj | j| j¡ W n2 ty } zt  d|¡ W Y d}~n
d}~0 0 dS )zR Initialize a connection to a client.

        Returns:
            None

        zWebSocket connection openedZbokehz!Subprotocol header is not 'bokeh'Nz'No token received in subprotocol headerZsession_expiryz$Session expiry has not been providedzToken is expired.)ZsignedÚ
secret_keyz*Token for session %r had invalid signaturezInvalid token signaturez"Failed to fully open connection %r)r@   Úinfor)   Zselected_subprotocolÚcloser   ÚcalendarZtimegmÚdtÚdatetimeZutcnowZutctimetupler   r   r>   Zsign_sessionsrC   r   rA   Zio_loopZadd_callbackÚ_async_openÚ	ExceptionÚdebug)r/   ÚtokenZnowZpayloadÚ
session_idÚer4   r4   r5   Úopen|   s6    




þzWSHandler.openz	List[str]z
str | None)Úsubprotocolsr   c                 C  s8   t  d¡ t  d|¡ t|ƒdks&d S |d | _|d S )NzSubprotocol header receivedz Supplied subprotocol headers: %rr   r   r   )r@   rK   ÚtraceÚlenr)   )r/   rP   r4   r4   r5   Úselect_subprotocol¥   s    

zWSHandler.select_subprotocolzDict[str, Any] | Nonec                 C  s0   | j d u rd S d| j i}| jd ur,| j|d< |S )Nr"   r#   )r+   r,   )r/   Zoptionsr4   r4   r5   Úget_compression_options­   s    



z!WSHandler.get_compression_options)rL   r   c              
   Ã  sà   z€t |ƒ}| j || j|¡I dH  | j |¡}tƒ }t|ƒ| _t 	d|¡ t
ƒ | _t 	d|¡ | j || | j|¡| _t d¡ W n< ty¼ } z$t d|¡ |  ¡  |‚W Y d}~n
d}~0 0 | jj d¡}|  |¡I dH  dS )a   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 handler
        * 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

        Returns:
            None

        NzReceiver created for %rzProtocolHandler created for %rzServerConnection createdz/Could not create new server session, reason: %sZACK)r   r    Zcreate_session_if_neededZrequestZget_sessionr   r   r$   r@   rK   r   r%   r>   Znew_connectionr&   rD   r   rA   rE   ÚprotocolZcreateÚsend_message)r/   rL   rM   ZsessionrU   rN   Úmsgr4   r4   r5   rI   µ   s$    
zWSHandler._async_openzstr | bytes)Úfragmentr   c              
   Ã  sà   z|   |¡I dH }W nD tyX } z,tjd||dd |  d¡ d}W Y d}~n
d}~0 0 z@|r˜tdurttj |¡ |  |¡I dH }|r˜|  	|¡I dH  W n@ tyÚ } z(tjd||dd |  d¡ W Y d}~n
d}~0 0 dS )a   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

        Nz/Unhandled exception receiving a message: %r: %rT©Úexc_infoz server failed to parse a messagez.Handler or its work threw an exception: %r: %rz!server failed to handle a message)
Ú_receiverJ   r@   rA   Ú_internal_errorÚ_message_test_portÚreceivedÚappendÚ_handleÚ	_schedule)r/   rX   ÚmessagerN   Úworkr4   r4   r5   Ú
on_messageá   s"    
 zWSHandler.on_messageÚbytes)Údatar   c                 C  s\   zt | d¡ƒ| _W nB ty6   tjd|dd Y n" tyV   tjd|dd Y n0 d S )Nzutf-8z#received invalid unicode in pong %rTrY   z#received invalid integer in pong %r)ÚintÚdecoder'   ÚUnicodeDecodeErrorr@   rQ   Ú
ValueError)r/   rf   r4   r4   r5   Úon_pong  s    zWSHandler.on_pongzMessage[Any])rb   r   c                 Ã  sJ   z(t durt j |¡ | | ¡I dH  W n tyD   t d¡ Y n0 dS )z‰ Send a Bokeh Server protocol message to the connected client.

        Args:
            message (Message) : a message to send

        Nz/Failed sending message as connection was closed)r]   Úsentr_   Úsendr   r@   Zwarning©r/   rb   r4   r4   r5   rV     s    zWSHandler.send_messageFTz!Union[bytes, str, Dict[str, Any]])rb   ÚbinaryÚlockedr   c                 ƒ  sb   |rJ| j  ¡ I dH $ tƒ  ||¡I dH  W d  ƒ q^1 s>0    Y  ntƒ  ||¡I dH  dS )zj Override parent write_message with a version that acquires a
        write lock before writing.

        N)r(   Úacquirer-   Úwrite_message)r/   rb   ro   rp   r2   r4   r5   rr   "  s    4zWSHandler.write_messagec                 C  s.   t  d| j| j¡ | jdur*| j | j¡ dS )z2 Clean up when the connection is closed.

        z/WebSocket connection closed: code=%s, reason=%rN)r@   rD   Z
close_codeZclose_reasonr&   r>   Zclient_lost)r/   r4   r4   r5   Úon_close.  s    
zWSHandler.on_closezMessage[Any] | Nonec              
   Ã  sX   z| j  |¡I d H }|W S  tttfyR } z|  t|ƒ¡ W Y d }~d S d }~0 0 d S r6   )r$   Zconsumer   r   r   Ú_protocol_errorr8   )r/   rX   rb   rN   r4   r4   r5   r[   6  s    zWSHandler._receivez
Any | Nonec              
   Ã  s\   z| j  || j¡I d H }|W S  tttfyV } z|  t|ƒ¡ W Y d }~d S d }~0 0 d S r6   )r%   Zhandler&   r   r   r   r\   r8   )r/   rb   rc   rN   r4   r4   r5   r`   ?  s    zWSHandler._handler   )rc   r   c                 Ã  s:   t |tƒr&|  ttt |ƒ¡I d H  n|  d|›¡ d S )Nzexpected a Message not )Ú
isinstancer   rV   r   r   r\   )r/   rc   r4   r4   r5   ra   H  s    
zWSHandler._schedulec                 C  s   t  d|¡ |  d|¡ d S )Nz3Bokeh Server internal error: %s, closing connectioni'  ©r@   rA   rE   rn   r4   r4   r5   r\   P  s    zWSHandler._internal_errorc                 C  s   t  d|¡ |  d|¡ d S )Nz3Bokeh Server protocol error: %s, closing connectioni'  rv   rn   r4   r4   r5   rt   T  s    zWSHandler._protocol_error)FT)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r.   r7   rB   r
   ZauthenticatedrO   rS   rT   rI   rd   rk   rV   rr   rs   r[   r`   ra   r\   rt   Ú__classcell__r4   r4   r2   r5   r   D   s(   (,'
 ÿ		r   c                   @  s   e Zd ZU ded< ded< dS )ÚMessageTestPortzList[Message[Any]]rl   r^   N)rw   rx   ry   Ú__annotations__r4   r4   r4   r5   r|   _  s   
r|   zMessageTestPort | Noner]   )3rz   Z
__future__r   ZloggingZ	getLoggerrw   r@   rF   rH   rG   Útypingr   r   r   r   r   Zurllib.parser   Ztornador	   r
   Ztornado.websocketr   r   Zbokeh.settingsr   Zbokeh.util.tokenr   r   r   rU   r   Zprotocol.exceptionsr   r   r   Zprotocol.messager   Zprotocol.receiverr   Zutil.dataclassesr   Zprotocol_handlerr   Z
auth_mixinr   Ú__all__r   r|   r]   r}   r4   r4   r4   r5   Ú<module>   s2   
  