o
    jR9                     @   s~   d Z ddlZddlZddlZddlZdZdZdZdZdZ	dZ
dZd	Zd
ZdZdZdZdZdZdZdZdZdZG dd dZdS )ze
WebSocket protocol handler for ASGI.

Implements RFC 6455 WebSocket protocol for ASGI applications.
    N         	   
   i  i  i  i  i  i  i  i  i  i  i  s$   258EAFA5-E914-47DA-95CA-C5AB0DC85B11c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zd"dd Zd!S )#WebSocketProtocolzWebSocket connection handler for ASGI applications.

    Uses callback-based data feeding instead of StreamReader for efficiency.
    Data is fed via feed_data() from the parent protocol's data_received().
    c                 C   sx   || _ || _|| _|| _d| _d| _d| _d| _d| _d| _	t
 | _g | _d| _t
 | _t | _t
 | _d| _dS )zInitialize WebSocket protocol handler.

        Args:
            transport: asyncio transport for writing
            scope: ASGI WebSocket scope dict
            app: ASGI application callable
            log: Logger instance
        FN )	transportscopeapplogacceptedclosed
close_codeclose_reason_close_sent_close_receivedasyncioEvent_close_event
_fragments_fragment_opcodeQueue_receive_queue	bytearray_buffer_data_event_eof)selfr	   r
   r   r    r   L/var/www/ai-app/venv/lib/python3.10/site-packages/gunicorn/asgi/websocket.py__init__1   s"   	



zWebSocketProtocol.__init__c                 C   s"   |r| j | | j  dS dS )zFeed incoming data from the parent protocol's data_received().

        Args:
            data: bytes received on the connection
        N)r   extendr   set)r   datar   r   r    	feed_dataU   s   zWebSocketProtocol.feed_datac                 C   s   d| _ | j  dS )z+Signal that the connection has been closed.TN)r   r   r#   r   r   r   r    feed_eof_   s   zWebSocketProtocol.feed_eofc                    s  | j ddiI dH  t|  }zgz| | j| j| jI dH  W n t	y2   | j
d Y nw W | jsc| jrc| jsc| tdI dH  ztj| j ddI dH  W n tjyb   d| _Y nw |  z|I dH  W dS  tjyz   Y dS w | js| jr| js| tdI dH  ztj| j ddI dH  W n tjy   d| _Y nw |  z|I dH  W w  tjy   Y w w )	z#Run the WebSocket ASGI application.typezwebsocket.connectNz#Error in WebSocket ASGI applicationzApplication error      @timeoutT)r   putr   create_task_read_framesr   r
   _receive_send	Exceptionr   	exceptionr   r   r   _send_closeCLOSE_INTERNAL_ERRORwait_forr   waitTimeoutErrorcancelCancelledError)r   	read_taskr   r   r    rund   sF   

zWebSocketProtocol.runc                    s   | j  I dH S )zASGI receive callable.N)r   getr&   r   r   r    r/      s   zWebSocketProtocol._receivec                    sL  |d }|dkr| j rtd| |I dH  d| _ dS |dkr\| j s(td| jr/td|d	}|d
}|durK| t|dI dH  dS |durZ| t|I dH  dS dS |dkr|dt	}|dd}| 
||I dH  ztj| j ddI dH  W n tjy   | jd d| _| j  Y nw | j  dS dS )zASGI send callable.r(   zwebsocket.acceptzWebSocket already acceptedNTzwebsocket.sendzWebSocket not acceptedzWebSocket closedtextbytesutf-8zwebsocket.closecodereasonr   r)   r*   z!WebSocket close handshake timeout)r   RuntimeError_send_acceptr   r<   _send_frameOPCODE_TEXTencodeOPCODE_BINARYCLOSE_NORMALr3   r   r5   r   r6   r7   r   debugr#   r	   close)r   messagemsg_typer=   
bytes_datar@   rA   r   r   r    r0      s@   


zWebSocketProtocol._sendc           	         s  d}| j d D ]\}}|dkr|} nq|stdtt|t  d}dddd	| d
g}|	d}|rD|
d| d
 |	dg }|D ]#\}}t|trZ|d}t|trd|d}|
| d| d
 qL|
d
 | jd|d dS )z)Send WebSocket handshake accept response.Nheaderss   sec-websocket-keyz Missing Sec-WebSocket-Key headerasciiz"HTTP/1.1 101 Switching Protocols
zUpgrade: websocket
zConnection: Upgrade
zSec-WebSocket-Accept: z
subprotocolzSec-WebSocket-Protocol: zlatin-1z: r   )r
   rB   base64	b64encodehashlibsha1WS_GUIDdigestdecoder<   append
isinstancer>   r	   writejoinrF   )	r   rK   ws_keynamevalue
accept_keyrN   rP   extra_headersr   r   r    rC      s>   






zWebSocketProtocol._send_acceptc                    s  zzu| j r| jrv| jsv|  I dH }|du rn^|\}}|tkr)| |I dH  nM|tkr7| t|I dH  n6|tkr<n1|t	krP| j
d|ddI dH  n|tkra| j
d|dI dH  n|tkrm| |I dH  | j r| jrv| jrW n! tjy     ty } z| jd| W Y d}~nd}~ww W | j sd| _ | j
d| jptd	I dH  dS dS | j sd| _ | j
d| jptd	I dH  w w )
z+Read and process incoming WebSocket frames.Nzwebsocket.receiver?   )r(   r=   )r(   r>   zWebSocket read error: %sTzwebsocket.disconnect)r(   r@   )r   r   r   _read_frameOPCODE_CLOSE_handle_closeOPCODE_PINGrD   OPCODE_PONGrE   r   r,   rW   rG   OPCODE_CONTINUATION_handle_continuationr   r9   r1   r   rI   r   CLOSE_ABNORMAL)r   frameopcodepayloader   r   r    r.      s`   
zWebSocketProtocol._read_framesc                    s  |  dI dH }|sdS |d |d }}|d? d@ }|d? d@ }|d? d@ }|d? d@ }|d	@ }|s8|s8|rC| td
I dH  dS |d? d@ }	|d@ }
|	sZ| tdI dH  dS |
dkrs|  dI dH }|sjdS td|d }
n|
dkr|  dI dH }|sdS td|d }
|  dI dH }|sdS |  |
I dH }|du rdS | ||}|tkr| jdu r| tdI dH  dS | j	| |rd
| j}| j}g | _d| _||fS tdfS |ttfv r|s|| _|g| _tdfS ||fS ||fS )z{Read a single WebSocket frame.

        Returns:
            tuple: (opcode, payload) or None if connection closed
        r   Nr   r                  zRSV bits set   zFrame not masked~   !Hr   !QzUnexpected continuation    )_read_exactr3   CLOSE_PROTOCOL_ERRORstructunpack_unmaskrf   r   r   rX   r[   rE   rG   )r   header
first_bytesecond_bytefinrsv1rsv2rsv3rj   maskedpayload_lenext_lenmasking_keyrk   full_payloadfinal_opcoder   r   r    ra     sl   
zWebSocketProtocol._read_framec                    s   t | j|k r5| jrdS | j  t | j|krn| j I dH  | jr.t | j|k r.dS t | j|k st| jd| }| jd|= |S )zRead exactly n bytes from internal buffer.

        Waits for data via the callback-fed buffer instead of StreamReader.
        N)lenr   r   r   clearr6   r>   )r   nr$   r   r   r    rw   X  s   
zWebSocketProtocol._read_exactc                    s"   |s|S t  fddt|D S )zUnmask WebSocket payload data.c                 3   s$    | ]\}}| |d   A V  qdS )rp   Nr   ).0ibr   r   r    	<genexpr>r  s   " z,WebSocketProtocol._unmask.<locals>.<genexpr>)r>   	enumerate)r   rk   r   r   r   r    r{   m  s   zWebSocketProtocol._unmaskc                    s   t |dkr!td|dd d | _|dd jddd| _nt| _d| _d	| _| js8| 	| j| jI dH  d	| _
| j  dS )
zHandle incoming close frame.r   rt   Nr   r?   replace)errorsr   T)r   ry   rz   r   rW   r   CLOSE_NO_STATUSr   r   r3   r   r   r#   r   rk   r   r   r    rc   t  s   zWebSocketProtocol._handle_closec                    s   dS )z=Handle continuation frame (already processed in _read_frame).Nr   r   r   r   r    rg     s    z&WebSocketProtocol._handle_continuationc                    s   t |tr|d}t|}t }|d|B  |dk r#|| n!|dk r6|d |td| n|d |td| || | j	
t| dS )	zRSend a WebSocket frame.

        Server frames are not masked (RFC 6455).
        r?      rs   i   rt   rr   ru   N)rY   strrF   r   r   rX   r"   ry   packr	   rZ   r>   )r   rj   rk   lengthri   r   r   r    rD     s   




zWebSocketProtocol._send_framer   c                    sh   | j rdS td|}|r||ddd 7 }| t|I dH  d| _ | jr2d| _| j	  dS dS )zSend a close frame.Nrt   r?   {   T)
r   ry   r   rF   rD   rb   r   r   r   r#   )r   r@   rA   rk   r   r   r    r3     s   zWebSocketProtocol._send_closeN)r   )__name__
__module____qualname____doc__r!   r%   r'   r;   r/   r0   rC   r.   ra   rw   r{   rc   rg   rD   r3   r   r   r   r    r   *   s"    $
(*0Rr   )r   r   rQ   rS   ry   rf   rE   rG   rb   rd   re   rH   CLOSE_GOING_AWAYrx   CLOSE_UNSUPPORTEDr   rh   CLOSE_INVALID_DATACLOSE_POLICY_VIOLATIONCLOSE_MESSAGE_TOO_BIGCLOSE_MANDATORY_EXTr4   rU   r   r   r   r   r    <module>   s0   