o
    tBhJ                     @   s   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m	Z	m
Z
mZmZ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 eeZG dd deZ dS )    N)suppress)
SSLContext)AnyDictListOptionalTupleUnioncast)DocumentNodeExecutionResult	print_ast)HeadersLike)Subprotocol   )TransportProtocolErrorTransportQueryErrorTransportServerError)WebsocketsTransportBasec                       sx  e Zd ZdZeedZeedZddi dddddddi dfded	e	e
 d
eeef deeef de	eeef  de	eeef  de	eeef  de	eeef  de	eeef  de	eeef  dedeeef de	ee  ddf fddZdHddZdHddZdd ZdIde	e ddfdd ZdIde	e ddfd!d"Zd#eddfd$d%Zd#eddfd&d'Zd#efd(d)ZdHd*d+Z		dJd,ed-e	eeef  d.e	e defd/d0Zd1d2 Zd3eeef de ee	e e	e! f fd4d5Z"d3eeef de ee	e e	e! f fd6d7Z#d8ede ee	e e	e! f fd9d:Z$dHd;d<Z%d=ed>e	e d?e	e! ddf fd@dAZ&dBdC Z'dDdE Z(dFdG Z)  Z*S )KWebsocketsTransportz:ref:`Async Transport <async_transports>` used to execute GraphQL queries on
    remote servers with websocket connection.

    This transport uses asyncio and the websockets library in order to send requests
    on a websocket connection.
    z
graphql-wszgraphql-transport-wsNF
   Turlheaderssslinit_payloadconnect_timeoutclose_timeoutack_timeoutkeep_alive_timeoutping_intervalpong_timeoutanswer_pingsconnect_argssubprotocolsreturnc                    s   t  |||||||||	 |	| _|  || _|	dur'|
du r$|	d | _n|
| _d| _t | _	 t | _		 |du rC| j
| jg| _dS || _dS )a  Initialize the transport with the given parameters.

        :param url: The GraphQL server URL. Example: 'wss://server.com:PORT/graphql'.
        :param headers: Dict of HTTP Headers.
        :param ssl: ssl_context of the connection. Use ssl=False to disable encryption
        :param init_payload: Dict of the payload sent in the connection_init message.
        :param connect_timeout: Timeout in seconds for the establishment
            of the websocket connection. If None is provided this will wait forever.
        :param close_timeout: Timeout in seconds for the close. If None is provided
            this will wait forever.
        :param ack_timeout: Timeout in seconds to wait for the connection_ack message
            from the server. If None is provided this will wait forever.
        :param keep_alive_timeout: Optional Timeout in seconds to receive
            a sign of liveness from the server.
        :param ping_interval: Delay in seconds between pings sent by the client to
            the backend for the graphql-ws protocol. None (by default) means that
            we don't send pings. Note: there are also pings sent by the underlying
            websockets protocol. See the
            :ref:`keepalive documentation <websockets_transport_keepalives>`
            for more information about this.
        :param pong_timeout: Delay in seconds to receive a pong from the backend
            after we sent a ping (only for the graphql-ws protocol).
            By default equal to half of the ping_interval.
        :param answer_pings: Whether the client answers the pings from the backend
            (for the graphql-ws protocol).
            By default: True
        :param connect_args: Other parameters forwarded to
            `websockets.connect <https://websockets.readthedocs.io/en/stable/reference/            client.html#opening-a-connection>`_
        :param subprotocols: list of subprotocols sent to the
            backend in the 'subprotocols' http header.
            By default: both apollo and graphql-ws subprotocols.
        N   )super__init__r   r!   r    send_ping_taskasyncioEventping_receivedpong_receivedAPOLLO_SUBPROTOCOLGRAPHQLWS_SUBPROTOCOLsupported_subprotocols)selfr   r   r   r   r   r   r   r   r   r    r!   r"   r#   	__class__ o/var/www/html/riverr-enterprise-integrations-main/venv/lib/python3.10/site-packages/gql/transport/websockets.pyr'   #   s8   2



zWebsocketsTransport.__init__c                    s@   	 |   I dH }| |\}}}|dkrdS |dkrtdq)zDWait for the connection_ack message. Keep alive messages are ignoredTNconnection_ackkaz0Websocket server did not return a connection ack)_receive_parse_answerr   )r0   init_answeranswer_type	answer_idexecution_resultr3   r3   r4   	_wait_ack}   s   zWebsocketsTransport._wait_ackc                    s@   t d| jd}| |I dH  t|  | jI dH  dS )zSend init message to the provided websocket and wait for the connection ACK.

        If the answer is not a connection_ack message, we will return an Exception.
        connection_init)typepayloadN)jsondumpsr   _sendr)   wait_forr=   r   )r0   init_messager3   r3   r4   _send_init_message_and_wait_ack   s   
z3WebsocketsTransport._send_init_message_and_wait_ackc                    s   |   I d H  d S N)rF   r0   r3   r3   r4   _initialize   s   zWebsocketsTransport._initializer@   c                    4   ddi}|dur||d< |  t|I dH  dS )z/Send a ping message for the graphql-ws protocolr?   pingNr@   rC   rA   rB   )r0   r@   ping_messager3   r3   r4   	send_ping   
   zWebsocketsTransport.send_pingc                    rJ   )z/Send a pong message for the graphql-ws protocolr?   pongNr@   rL   )r0   r@   pong_messager3   r3   r4   	send_pong   rO   zWebsocketsTransport.send_pongquery_idc                    *   t t|dd}| |I dH  dS )zSend stop message to the provided websocket connection and query_id.

        The server should afterwards return a 'complete' message.
        stopidr?   NrA   rB   strrC   )r0   rS   stop_messager3   r3   r4   _send_stop_message      z&WebsocketsTransport._send_stop_messagec                    rT   )znSend a complete message for the provided query_id.

        This is only for the graphql-ws protocol.
        completerV   NrX   )r0   rS   complete_messager3   r3   r4   _send_complete_message   r\   z*WebsocketsTransport._send_complete_messagec                    s\   t d|  | j| jkr$| |I dH  | j| dI dH  dS | |I dH  dS )ao  Stop the listener corresponding to the query_id depending on the
        detected backend protocol.

        For apollo: send a "stop" message
                    (a "complete" message will be sent from the backend)

        For graphql-ws: send a "complete" message and simulate the reception
                        of a "complete" message from the backend
        zstop listener N)r]   N)logdebugsubprotocolr.   r_   	listenersputr[   )r0   rS   r3   r3   r4   _stop_listener   s   
z"WebsocketsTransport._stop_listenerc                    s$   t ddi}| |I dH  dS )zSend a connection_terminate message to the provided websocket connection.

        This message indicates that the connection will disconnect.
        r?   connection_terminateN)rA   rB   rC   )r0   connection_terminate_messager3   r3   r4   "_send_connection_terminate_message   s   z6WebsocketsTransport._send_connection_terminate_messagedocumentvariable_valuesoperation_namec                    sx   | j }|  j d7  _ dt|i}|r||d< |r||d< d}| j| jkr'd}tt|||d}| |I dH  |S )	zSend a query to the provided websocket connection.

        We use an incremented id to reference the query.

        Returns the used id for this query.
        r   query	variablesoperationNamestart	subscribe)rW   r?   r@   N)next_query_idr   rb   r.   rA   rB   rY   rC   )r0   ri   rj   rk   rS   r@   
query_type	query_strr3   r3   r4   _send_query   s    zWebsocketsTransport._send_queryc                    s$   | j | jkr|  I d H  d S d S rG   )rb   r-   rh   rH   r3   r3   r4   _connection_terminate  s   z)WebsocketsTransport._connection_terminatejson_answerc              
   C   sD  d}d}d}zt |d}|dv rmtt |d}|dks#|dkrl|d}|dkrTt|ts5td	d
|vrAd|vrAtdt|d
|d|dd}d}n)|dkrlt|tsatdtt |d ||dn|dv r{|dd| j	|< nt| j
dur| j  W n ty } ztd| |d}~ww |||fS )a  Parse the answer received from the server if the server supports the
        graphql-ws protocol.

        Returns a list consisting of:
            - the answer_type (between:
              'connection_ack', 'ping', 'pong', 'data', 'error', 'complete')
            - the answer id (Integer) if received or None
            - an execution Result if the answer_type is 'data' or None

        Differences with the apollo websockets protocol (superclass):
            - the "data" message is now called "next"
            - the "stop" message is now called "complete"
            - there is no connection_terminate or connection_error messages
            - instead of a unidirectional keep-alive (ka) message from server to client,
              there is now the possibility to send bidirectional ping/pong messages
            - connection_ack has an optional payload
            - the 'error' answer type returns a list of errors instead of a single error
         Nr?   )nexterrorr]   rW   rx   ry   r@   payload is not a dicterrorsdata2payload does not contain 'data' or 'errors' fields
extensionsr{   r|   r~   zpayload is not a listr   rS   r{   )rK   rP   r5   (Server did not return a GraphQL result: )rY   getint
isinstancedict
ValueErrorr   listr   payloadscheck_keep_alive_task_next_keep_alive_messagesetr   )r0   rv   r:   r;   r<   r@   er3   r3   r4   _parse_answer_graphqlws
  sX   





z+WebsocketsTransport._parse_answer_graphqlwsc              
   C   sJ  d}d}d}zt |d}|dv ratt |d}|dks#|dkr`|d}t|ts1td	|dkrRd
|vrAd|vrAtdt|d
|d|dd}n8|dkr`tt |||gdn)|dkrp| jduro| j	
  n|dkrun|dkr|d}tdt| dtW n ty } ztd| |d}~ww |||fS )a  Parse the answer received from the server if the server supports the
        apollo websockets protocol.

        Returns a list consisting of:
            - the answer_type (between:
              'connection_ack', 'ka', 'connection_error', 'data', 'error', 'complete')
            - the answer id (Integer) if received or None
            - an execution Result if the answer_type is 'data' or None
        rw   Nr?   )r|   ry   r]   rW   r|   ry   r@   rz   r{   r}   r~   r   r   r6   r5   connection_errorzServer error: ''r   )rY   r   r   r   r   r   r   r   r   r   r   r   reprr   )r0   rv   r:   r;   r<   r@   error_payloadr   r3   r3   r4   _parse_answer_apolloZ  s\   





z(WebsocketsTransport._parse_answer_apolloanswerc                 C   sL   zt |}W n ty   td| w | j| jkr!| |S | |S )zaParse the answer received from the server depending on
        the detected subprotocol.
        r   )rA   loadsr   r   rb   r.   r   r   )r0   r   rv   r3   r3   r4   r8     s   

z!WebsocketsTransport._parse_answerc                    s   | j dusJ z$	 t| j I dH  |  I dH  t| j | jI dH  | j  q
 tj	yP   | j
du rM| jtd| jdddI dH  Y dS Y dS w )a  Coroutine to periodically send a ping from the client to the backend.

        Only used for the graphql-ws protocol.

        Send a ping every ping_interval seconds.
        Close the connection if a pong is not received within pong_timeout seconds.
        NTzNo pong received after z secondsF)clean_close)r   r)   sleeprN   rD   r,   waitr    clearTimeoutError
close_task_failr   rH   r3   r3   r4   _send_ping_coro  s&   	


z#WebsocketsTransport._send_ping_coror:   r;   r<   c                    s`   t  |||I d H  |dkr#| j  | jr!|  I d H  d S d S |dkr.| j  d S d S )NrK   rP   )r&   _handle_answerr+   r   r!   rR   r,   )r0   r:   r;   r<   r1   r3   r4   r     s   
z"WebsocketsTransport._handle_answerc                    sJ   | j j}z|d | _W n ty   | j| _Y nw td| j d S )NzSec-WebSocket-Protocolzbackend subprotocol returned: )	websocketresponse_headersrb   KeyErrorr-   r`   ra   )r0   r   r3   r3   r4   _after_connect  s   z"WebsocketsTransport._after_connectc                    s4   | j | jkr| jd urt|  | _d S d S d S rG   )rb   r.   r   r)   ensure_futurer   r(   rH   r3   r3   r4   _after_initialize  s   
z%WebsocketsTransport._after_initializec                    sZ   | j d ur+| j   ttj | j I d H  W d    n1 s!w   Y  d | _ d S d S rG   )r(   cancelr   r)   CancelledErrorrH   r3   r3   r4   _close_hook  s   


zWebsocketsTransport._close_hook)r$   NrG   )NN)+__name__
__module____qualname____doc__r
   r   r-   r.   rY   r   r   r	   r   boolr   r   r   floatr   r'   r=   rF   rI   rN   rR   r[   r_   re   rh   r   rt   ru   r   r   r   r   r8   r   r   r   r   r   __classcell__r3   r3   r1   r4   r      s    
	


	



Z






#

P

D

!
r   )!r)   rA   logging
contextlibr   r   r   typingr   r   r   r   r   r	   r
   graphqlr   r   r   websockets.datastructuresr   websockets.typingr   
exceptionsr   r   r   websockets_baser   	getLoggerr   r`   r   r3   r3   r3   r4   <module>   s    $
