o
    tBhK;                     @   s   d dl Z d dlZd dlZd dl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mZmZ ddlmZ eeZG dd	 d	ZG d
d deZdS )    N)AnyDictOptionalTuple)DocumentNodeExecutionResult	print_ast)ConnectionClosed   )TransportProtocolErrorTransportQueryErrorTransportServerError)WebsocketsTransportBasec                   @   s"   e Zd ZdZdeddfddZdS )Subscriptionz@Records listener_id and unsubscribe query_id for a subscription.query_idreturnNc                 C   s   || _ d | _d S N)listener_idunsubscribe_idselfr    r   /var/www/html/riverr-enterprise-integrations-main/venv/lib/python3.10/site-packages/gql/transport/phoenix_channel_websockets.py__init__   s   
zSubscription.__init__)__name__
__module____qualname____doc__intr   r   r   r   r   r      s    r   c                	       sP  e Zd ZdZ		d-dededdf fdd	Zd.d
dZdeddfddZ	deddfddZ
d.ddZdd Z		d/dedeeeef  dee defddZdedeeee ee f fddZdedee dee ddf fd d!Zdeddf fd"d#Zdedeee ef fd$d%Zdedefd&d'Zd0d)ed*eddf fd+d,Z  ZS )1!PhoenixChannelWebsocketsTransportat  The PhoenixChannelWebsocketsTransport is an async transport
    which allows you to execute queries and subscriptions against an `Absinthe`_
    backend using the `Phoenix`_ framework `channels`_.

    .. _Absinthe: http://absinthe-graphql.org
    .. _Phoenix: https://www.phoenixframework.org
    .. _channels: https://hexdocs.pm/phoenix/Phoenix.Channel.html#content
    __absinthe__:control   channel_nameheartbeat_intervalr   Nc                    s2   || _ || _d| _i | _tt| j|i | dS )aF  Initialize the transport with the given parameters.

        :param channel_name: Channel on the server this transport will join.
            The default for Absinthe servers is "__absinthe__:control"
        :param heartbeat_interval: Interval in second between each heartbeat messages
            sent by the client
        N)r"   r#   heartbeat_tasksubscriptionssuperr   r   )r   r"   r#   argskwargs	__class__r   r   r   %   s
   z*PhoenixChannelWebsocketsTransport.__init__c                    s    j }  j d7  _ t jdi |d} |I dH  t   jI dH } 	|\}}}|dkr:t
d fdd}t|  _dS )	zJoin the specified channel and wait for the connection ACK.

        If the answer is not a connection_ack message, we will return an Exception.
        r
   phx_jointopiceventpayloadrefNreplyz0Websocket server did not return a connection ackc               	      sf   	 t  jI d H  z j}   jd7  _ tddi | dI d H  W n
 ty1   Y d S w q)NTr
   phoenix	heartbeatr,   )asynciosleepr#   next_query_id_sendjsondumpsr	   r   r   r   r   heartbeat_coroW   s&   
zEPhoenixChannelWebsocketsTransport._initialize.<locals>.heartbeat_coro)r6   r8   r9   r"   r7   r4   wait_for_receiveack_timeout_parse_answerr   ensure_futurer$   )r   r   init_messageinit_answeranswer_type	answer_idexecution_resultr<   r   r;   r   _initialize9   s&   	z-PhoenixChannelWebsocketsTransport._initializer   c                    sZ   |  |}| j}|  jd7  _|| j| _t| jdd|i|d}| |I dH  dS )a"  Send an 'unsubscribe' message to the Phoenix Channel referencing
        the listener's query_id, saving the query_id of the message.

        The server should afterwards return a 'phx_reply' message with
        the same query_id and subscription_id of the 'unsubscribe' request.
        r
   unsubscribesubscriptionIdr,   N)_find_existing_subscriptionr6   r%   r   r8   r9   r"   r7   )r   r   subscription_idunsubscribe_query_idunsubscribe_messager   r   r   _send_stop_messagem   s   
	z4PhoenixChannelWebsocketsTransport._send_stop_messagec                    s   |  |I d H  d S r   )rN   r   r   r   r   _stop_listener   s   z0PhoenixChannelWebsocketsTransport._stop_listenerc                    s@   | j }|  j d7  _ t| jdi |d}| |I dH  dS )zASend a phx_leave message to disconnect from the provided channel.r
   	phx_leaver,   N)r6   r8   r9   r"   r7   )r   r   connection_terminate_messager   r   r   "_send_connection_terminate_message   s   	zDPhoenixChannelWebsocketsTransport._send_connection_terminate_messagec                    s   |   I d H  d S r   )rR   r;   r   r   r   _connection_terminate   s   z7PhoenixChannelWebsocketsTransport._connection_terminatedocumentvariable_valuesoperation_namec                    sN   | j }|  j d7  _ t| jdt||pi d|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
   doc)query	variablesr,   N)r6   r8   r9   r"   r   r7   )r   rT   rU   rV   r   	query_strr   r   r   _send_query   s   z-PhoenixChannelWebsocketsTransport._send_queryanswerc              
      s
  d}d}d}d}d}dt dtdtdt fdd dt dtdtdt f fd	d
	d4dt dtdtdtffdd}dt dtdtfdd}zt|}	t|	dd}|dkr|	dd}
||
ddd}||
dd}d}j| }|j}t	|d|d|dd}n|dkrIt
|	dd}|	dd}
 |
dd}|dkrd }|jv r|
d!d}t|trd"|v r||d!dd#}t|j|< n||d!}d}t	|d|d|dd}n}|\}}|dur|
d!d}||d!}||krtd$d%}|}nX|d&kr<|
d!}t|tr6d|v r&tt|d|d'd(|v r6tt|d(|d'td)|d'|d*krGtd+|d'	 n|d,krRtd-|d.krZd/}ntd0W n  ty } ztd1| d2| td3||d}~ww |||fS )5a6  Parse the answer received from the server

        Returns a list consisting of:
            - the answer_type (between:
              'data', 'reply', 'complete', 'close')
            - the answer id (Integer) if received or None
            - an execution Result if the answer_type is 'data' or None
         Ndkeylabelr   c                 S   s"   t | tst| d| |S )N is not a dict)
isinstancedict
ValueErrorget)r^   r_   r`   r   r   r   
_get_value   s   

zCPhoenixChannelWebsocketsTransport._parse_answer.<locals>._get_valuec                    s,    | ||}|d u rt d| d| |S )Nznull z in )rd   )r^   r_   r`   value)rf   r   r   _required_value   s   zHPhoenixChannelWebsocketsTransport._parse_answer.<locals>._required_valueF
must_existc                    s@   t  | d|}|r|jvrtd|r|jv rtd|S )NrI   zunregistered subscriptionIdz$previously registered subscriptionId)strr%   rd   )r^   r`   ri   must_not_existrK   )rh   r   r   r   _required_subscription_id   s   zRPhoenixChannelWebsocketsTransport._parse_answer.<locals>._required_subscription_idc                 S   sX   t | tst| dt|  }|h d }t|dkr*t| dd| | S )zMake sure query, mutation or subscription answer conforms.
            The GraphQL spec says only three keys are permitted.
            ra   >   dataerrors
extensionsr   z contains invalid items: z, )rb   rc   rd   setkeyslenjoin)r^   r`   rq   invalidr   r   r   _validate_data_response   s   
zPPhoenixChannelWebsocketsTransport._parse_answer.<locals>._validate_data_responser.   r\   zsubscription:datar/   T)ri   resultrm   rn   ro   )rm   rn   ro   	phx_replyr0   statusokr1   responserI   )rk   zsubscription id does not matchcompleteerrorr:   reasonzreply errortimeoutzreply timeout	phx_errorzServer error	phx_closeclosezunrecognized eventzError parsing answer 'z': z(Server did not return a GraphQL result: )FF)r   rj   boolrc   r8   loadsre   r%   r   r   r   	listenersrb   r   _find_subscriptionrd   r   r   logr|   r   )r   r\   r.   rE   rD   rF   rK   rl   ru   json_answerr/   rv   subscriptionrx   rz   registered_subscription_idr   er   )rf   rh   r   r   r@      s   





	









z/PhoenixChannelWebsocketsTransport._parse_answerrD   rE   rF   c                    s6   |dkr|   I d H  d S t |||I d H  d S )Nr   )r   r&   _handle_answer)r   rD   rE   rF   r)   r   r   r   o  s   z0PhoenixChannelWebsocketsTransport._handle_answerc                    s:   z|  |}| j|= W n	 ty   Y nw t | dS )z<If the listener was a subscription, remove that information.N)rJ   r%   	Exceptionr&   _remove_listener)r   r   rK   r)   r   r   r   z  s   
z2PhoenixChannelWebsocketsTransport._remove_listenerc                 C   sJ   | j  D ]\}}||jkr||f  S ||jkr ||jf  S qd|fS )ePerform a reverse lookup to find the subscription id matching
        a listener's query_id.
        N)r%   itemsr   r   )r   r   rK   r   r   r   r   r     s   

z4PhoenixChannelWebsocketsTransport._find_subscriptionc                 C   s(   |  |\}}|du rtd| |S )r   Nz(No subscription registered for listener )r   r   )r   r   rK   _listener_idr   r   r   rJ     s   z=PhoenixChannelWebsocketsTransport._find_existing_subscriptionTr   clean_closec                    s.   | j d ur| j   t ||I d H  d S r   )r$   cancelr&   _close_coro)r   r   r   r)   r   r   r     s   

z-PhoenixChannelWebsocketsTransport._close_coro)r    r!   )r   N)NN)T)r   r   r   r   rj   floatr   rG   r   rN   rO   rR   rS   r   r   r   r   r[   r   r   r@   r   r   r   rJ   r   r   r   __classcell__r   r   r)   r   r      s\    
4

 
 3	$r   )r4   r8   loggingtypingr   r   r   r   graphqlr   r   r   websockets.exceptionsr	   
exceptionsr   r   r   websockets_baser   	getLoggerr   r   r   r   r   r   r   r   <module>   s    
