
    AҐia                        d Z ddlZddlZddlZddlmZ ddlm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e
eeeeeeeeeeeeeeeiZej7                         D  ci c]  \  } }|| 
 c}} 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) ejT                  e)      Z+dZ, G d d      Z-e-Z.	 d.de/d e/d!e0d"e1d#e1f
d$Z2d#e1fd%Z3d#e1fd&Z4d#e1fd'Z5d#e1fd(Z6	 d/d)e7d*e/d#e1fd+Z8d0d)e7d,e7d#e1fd-Z9yc c}} w )1a6  
Dirty Worker Binary Protocol

Binary message framing over Unix sockets, inspired by OpenBSD msgctl/msgsnd.
Replaces JSON protocol for efficient binary data transfer.

Header Format (16 bytes):
+--------+--------+--------+--------+--------+--------+--------+--------+
|  Magic (2B)     | Ver(1) | MType  |        Payload Length (4B)        |
+--------+--------+--------+--------+--------+--------+--------+--------+
|                       Request ID (8 bytes)                            |
+--------+--------+--------+--------+--------+--------+--------+--------+

- Magic: 0x47 0x44 ("GD" for Gunicorn Dirty)
- Version: 0x01
- MType: Message type (REQUEST, RESPONSE, ERROR, CHUNK, END)
- Length: Payload size (big-endian uint32, max 64MB)
- Request ID: uint64 (replaces UUID string)

Payload is TLV-encoded (see tlv.py).
    N   )DirtyProtocolError)
TLVEncoders   GD                     requestresponseerrorchunkendstashstatusmanage         	   
   z>2sBBIQi   c                      e Zd ZdZeZeZeZeZ	e
ZeZeZeZeZeZededededefd       Zededefd       Ze	 d%ded
ededededefd       Zededefd       Zededefd       Z ededefd       Z!ededefd       Z"ededefd       Z#ed&dedededefd       Z$e	 d'dedededefd       Z%ededefd       Z&ede'jP                  defd       Z)ede'jT                  dedd	fd       Z+ede,jX                  d edefd!       Z-ede,jX                  defd"       Z.ede,jX                  dedd	fd#       Z/ededefd$       Z0y	)(BinaryProtocolz-Binary message protocol for dirty worker IPC.msg_type
request_idpayload_lengthreturnc                 N    t        j                  t        t        t        | ||      S )a,  
        Encode the 16-byte message header.

        Args:
            msg_type: Message type (MSG_TYPE_REQUEST, etc.)
            request_id: Unique request identifier (uint64)
            payload_length: Length of the TLV-encoded payload

        Returns:
            bytes: 16-byte header
        )structpackHEADER_FORMATMAGICVERSION)r   r   r   s      P/var/www/descvideos/venv/lib/python3.12/site-packages/gunicorn/dirty/protocol.pyencode_headerzBinaryProtocol.encode_headerr   s"     {{=%():7 	7    datac                    t        |       t        k  r t        dt        |        dt         |       t        j                  t
        | dt               \  }}}}}|t        k7  rt        d|dt        | dd       |t        k7  rt        d| dt         | dd       |t        vrt        d	|d
| dd       |t        kD  rt        d| dt         d      |||fS )z
        Decode the 16-byte message header.

        Args:
            data: 16 bytes of header data

        Returns:
            tuple: (msg_type, request_id, payload_length)

        Raises:
            DirtyProtocolError: If header is invalid
        zHeader too short:  bytes, expected raw_dataNzInvalid magic: z, expected    zUnsupported protocol version: zUnknown message type: 0x02xzMessage too large: z bytes (max: ))
lenHEADER_SIZEr   r!   unpackr#   r$   r%   MSG_TYPE_TO_STRMAX_MESSAGE_SIZE)r)   magicversionr   lengthr   s         r&   decode_headerzBinaryProtocol.decode_header   s"    t9{"$$SYK/@N 
 8>}}4-8
4w&* E>$!%+eY?cr 
 g$0	WINcr 
 ?*$*8C.9cr 
 $$$%fX];K:LAN  V++r(   Napp_pathactionargskwargsc                     |||rt        |      ng |xs i d}t        j                  |      }t        j	                  t
        | t        |            }||z   S )al  
        Encode a request message.

        Args:
            request_id: Unique request identifier (uint64)
            app_path: Import path of the dirty app
            action: Action to call on the app
            args: Positional arguments
            kwargs: Keyword arguments

        Returns:
            bytes: Complete message (header + payload)
        )r:   r;   r<   r=   )listr   encoder   r'   MSG_TYPE_REQUESTr1   )r   r:   r;   r<   r=   payload_dictpayloadheaders           r&   encode_requestzBinaryProtocol.encode_request   s\    " !"&DJBl	
 ##L1--.>
.1'l<r(   c                     d|i}t        j                  |      }t        j                  t        | t        |            }||z   S )a  
        Encode a success response message.

        Args:
            request_id: Request identifier this responds to
            result: Result value (must be TLV-serializable)

        Returns:
            bytes: Complete message (header + payload)
        result)r   r@   r   r'   MSG_TYPE_RESPONSEr1   )r   rG   rB   rC   rD   s        r&   encode_responsezBinaryProtocol.encode_response   sE     !&)##L1--.?.1'l<r(   c                 6   ddl m} t        ||      r|j                         }n5t        |t              r|}n"t        |      j                  t        |      i d}d|i}t        j                  |      }t        j                  t        | t        |            }||z   S )a  
        Encode an error response message.

        Args:
            request_id: Request identifier this responds to
            error: DirtyError instance, dict, or Exception

        Returns:
            bytes: Complete message (header + payload)
        r   
DirtyError
error_typemessagedetailsr   )errorsrL   
isinstanceto_dictdicttype__name__strr   r@   r   r'   MSG_TYPE_ERRORr1   )r   r   rL   
error_dictrB   rC   rD   s          r&   encode_errorzBinaryProtocol.encode_error   s     	'eZ(Jt$J #5k22u:J  ,##L1--nj.1'l<r(   c                     d|i}t        j                  |      }t        j                  t        | t        |            }||z   S )a  
        Encode a chunk message for streaming responses.

        Args:
            request_id: Request identifier this chunk belongs to
            data: Chunk data (must be TLV-serializable)

        Returns:
            bytes: Complete message (header + payload)
        r)   )r   r@   r   r'   MSG_TYPE_CHUNKr1   )r   r)   rB   rC   rD   s        r&   encode_chunkzBinaryProtocol.encode_chunk   sC     ~##L1--nj.1'l<r(   c                 <    t         j                  t        | d      }|S )z
        Encode an end-of-stream message.

        Args:
            request_id: Request identifier this ends

        Returns:
            bytes: Complete message (header + empty payload)
        r   )r   r'   MSG_TYPE_ENDr   rD   s     r&   
encode_endzBinaryProtocol.encode_end  s      --lJJr(   c                 <    t         j                  t        | d      }|S )z
        Encode a status query message.

        Args:
            request_id: Request identifier

        Returns:
            bytes: Complete message (header + empty payload)
        r   )r   r'   MSG_TYPE_STATUSr`   s     r&   encode_statuszBinaryProtocol.encode_status   s      --oz1Mr(   opcountc                     ||d}t        j                  |      }t        j                  t        | t        |            }||z   S )a4  
        Encode a worker management message.

        Args:
            request_id: Request identifier
            op: Management operation (MANAGE_OP_ADD or MANAGE_OP_REMOVE)
            count: Number of workers to add/remove

        Returns:
            bytes: Complete message (header + payload)
        )re   rf   )r   r@   r   r'   MSG_TYPE_MANAGEr1   )r   re   rf   rB   rC   rD   s         r&   encode_managezBinaryProtocol.encode_manage/  sI     
 ##L1--oz.1'l<r(   tablec                     ||d}|||d<   |||d<   |||d<   t        j                  |      }t        j                  t        | t        |            }||z   S )a  
        Encode a stash operation message.

        Args:
            request_id: Unique request identifier (uint64)
            op: Stash operation code (STASH_OP_*)
            table: Table name
            key: Optional key for put/get/delete operations
            value: Optional value for put operation
            pattern: Optional pattern for keys operation

        Returns:
            bytes: Complete message (header + payload)
        )re   rj   keyvaluepattern)r   r@   r   r'   MSG_TYPE_STASHr1   )	r   re   rj   rl   rm   rn   rB   rC   rD   s	            r&   encode_stashzBinaryProtocol.encode_stashE  sx    $ 
 ?"%L$)L!&-L###L1--nj.1'l<r(   c                 |   t         j                  |       \  }}}t        |       t        |z   k  r&t	        dt        |z    dt        |        | dd       |dk(  ri }n&| t        t        |z    }	 t        j                  |      }t        |   }|||fS # t        $ r  t        $ r}t	        d| |dd       d}~ww xY w)a  
        Decode a complete message (header + payload).

        Args:
            data: Complete message bytes

        Returns:
            tuple: (msg_type_str, request_id, payload_dict)
                   msg_type_str is the string name (e.g., "request")
                   payload_dict is the decoded TLV payload as a dict

        Raises:
            DirtyProtocolError: If message is malformed
        zIncomplete message: expected z bytes, got N2   r,   r   Failed to decode TLV payload: )	r   r9   r1   r2   r   r   decode_full	Exceptionr4   )r)   r   r   r8   rB   payload_dataemsg_type_strs           r&   decode_messagezBinaryProtocol.decode_messagef  s      (6'C'CD'I$*ft9{V++$/f0D/E F4yk#cr  Q;LK&,@AL)55lC 'x0Z55 &  (4QC8)#2. s   .B B;#B66B;readerc                   K   	 | j                  t               d{   }t        j                  |      \  }}}|dkD  r1	 | j                  |       d{   }	 t        j                  |      }ni }t        |   }||d	}	|	j                  |       |	S 7 v# t        j                  $ rR}t	        |j
                        dk(  r t        dt	        |j
                         dt         |j
                        d}~ww xY w7 # t        j                  $ r5}t        dt	        |j
                         d| |j
                        d}~ww xY w# t        $ r  t        $ r}t        d| |dd       d}~ww xY ww)
ap  
        Read a complete binary message from async stream.

        Args:
            reader: asyncio StreamReader

        Returns:
            dict: Message dict with 'type', 'id', and payload fields

        Raises:
            DirtyProtocolError: If read fails or message is malformed
            asyncio.IncompleteReadError: If connection closed mid-read
        Nr   zIncomplete header: got r+   r,   zIncomplete payload: got rs   rr   rU   id)readexactlyr2   asyncioIncompleteReadErrorr1   partialr   r   r9   r   rt   ru   r4   update)
rz   rD   rw   r   r   r8   rv   rB   rx   rG   s
             r&   read_message_asyncz!BinaryProtocol.read_message_async  s     
	!--k::F (6'C'CF'K$*f A:%+%7%7%??)55lC L 'x0&j9l#S ;** 	199~"$)#aii.)9 :'=* 		  @.. (.s199~.> ?  &x)YY  &  (4QC8)#2. s   E7B BB E7 C? C=C? E
 /$E7B C:(AC55C::E7=C? ?E0EEE7
E4E//E44E7writerrO   c                    K   t         j                  |      }| j                  |       | j                          d{    y7 w)a[  
        Write a message to async stream.

        Accepts dict format for backwards compatibility.

        Args:
            writer: asyncio StreamWriter
            message: Message dict with 'type', 'id', and payload fields

        Raises:
            DirtyProtocolError: If encoding fails
            ConnectionError: If write fails
        N)r   _encode_from_dictwritedrain)r   rO   r)   s      r&   write_message_asyncz"BinaryProtocol.write_message_async  s3       //8Tllns   :AAAsocknc                     d}t        |      |k  rh| j                  |t        |      z
        }|s5t        |      dk(  rt        d      t        dt        |       d| |      ||z  }t        |      |k  rh|S )a  
        Receive exactly n bytes from a socket.

        Args:
            sock: Socket to read from
            n: Number of bytes to read

        Returns:
            bytes: Received data

        Raises:
            DirtyProtocolError: If read fails or connection closed
        r(   r   zConnection closedzConnection closed after r+   r,   )r1   recvr   )r   r   r)   r   s       r&   _recv_exactlyzBinaryProtocol._recv_exactly  s     $i!mIIa#d)m,Et9>,-@AA(.s4yk9J1#N!  EMD $i!m r(   c                 l   t         j                  | t              }t         j                  |      \  }}}|dkD  r-t         j                  | |      }	 t	        j
                  |      }ni }t        |   }||d}	|	j                  |       |	S # t        $ r  t        $ r}t        d| |dd       d}~ww xY w)a   
        Read a complete message from socket (sync).

        Args:
            sock: Socket to read from

        Returns:
            dict: Message dict with 'type', 'id', and payload fields

        Raises:
            DirtyProtocolError: If read fails or message is malformed
        r   rs   Nrr   r,   r|   )
r   r   r2   r9   r   rt   r   ru   r4   r   )
r   rD   r   r   r8   rv   rB   rw   rx   rG   s
             r&   read_messagezBinaryProtocol.read_message  s      --dK@'5'C'CF'K$*f A:)77fEL)55lC L 'x0&j9l# &  (4QC8)#2. s   B	 	B3B..B3c                 P    t         j                  |      }| j                  |       y)a  
        Write a message to socket (sync).

        Args:
            sock: Socket to write to
            message: Message dict with 'type', 'id', and payload fields

        Raises:
            DirtyProtocolError: If encoding fails
            OSError: If write fails
        N)r   r   sendall)r   rO   r)   s      r&   write_messagezBinaryProtocol.write_message/  s      //8Tr(   c           
         | j                  d      }| j                  dd      }t        |t              rt        |      dz  }t        j                  |      }|t        d|       |t        k(  rWt        j                  || j                  dd      | j                  dd      | j                  d	      | j                  d
            S |t        k(  r%t        j                  || j                  d            S |t        k(  r&t        j                  || j                  di             S |t        k(  r%t        j                  || j                  d            S |t        k(  rt        j!                  |      S |t"        k(  rft        j%                  || j                  d      | j                  dd      | j                  d      | j                  d      | j                  d            S |t&        k(  rt        j)                  |      S |t*        k(  r6t        j-                  || j                  d      | j                  dd            S t        d|       )a  
        Encode a message dict to binary format.

        Supports the old dict-based API for backwards compatibility.

        Args:
            message: Message dict with 'type', 'id', and payload fields

        Returns:
            bytes: Complete encoded message
        rU   r}   r   l    zUnknown message type: r:    r;   r<   r=   rG   r   r)   re   rj   rl   rm   rn   rf   r   zUnhandled message type: )getrR   rW   hashMSG_TYPE_FROM_STRr   rA   r   rE   rH   rI   rX   rZ   r\   r]   r_   ra   ro   rp   rc   rd   rh   ri   )rO   rx   r   r   s       r&   r   z BinaryProtocol._encode_from_dict?  s     {{6*[[q)
 j#&j),>>J$((6$'=l^%LMM''!00J+Hb)F#H%  **!11H%  '!..GR(  '!..F#  %!,,Z88'!..D!GR(E"G$I&  (!//
;;(!//D!GQ'  %'?z%JKKr(   NNr   NNN)1rV   
__module____qualname____doc__r2   r5   MSG_TYPE_REQUEST_STRrA   MSG_TYPE_RESPONSE_STRrH   MSG_TYPE_ERROR_STRrX   MSG_TYPE_CHUNK_STRr\   MSG_TYPE_END_STRr_   MSG_TYPE_STASH_STRro   MSG_TYPE_STATUS_STRrc   MSG_TYPE_MANAGE_STRrh   staticmethodintbytesr'   tupler9   rW   rT   rE   rI   rZ   r]   ra   rd   ri   rp   ry   r   StreamReaderr   StreamWriterr   socketr   r   r   r    r(   r&   r   r   b   s   7 K'+-'N'N#L'N)O)O7 7 7c 7e 7 7 .,E .,e ., .,` :> 3  #  s  " 37 CH   4  C  E    "        <    u    " s u   # %    #  3  s  5    * 37   #  c  <A   @ *6U *6u *6 *6` 9)=)= 9$ 9 9v '*>*> +/48 . FMM c e  6 %6== %T % %N FMM D T   CL4 CLE CL CLr(   r   r:   r;   r<   r=   r   c                 R    t         j                  | |||rt        |      ng |xs i dS )aU  
    Build a request message dict.

    Args:
        request_id: Unique request identifier (int or str)
        app_path: Import path of the dirty app (e.g., 'myapp.ml:MLApp')
        action: Action to call on the app
        args: Positional arguments
        kwargs: Keyword arguments

    Returns:
        dict: Request message dict
    )rU   r}   r:   r;   r<   r=   )DirtyProtocolrA   r?   )r   r:   r;   r<   r=   s        r&   make_requestr     s2      .."T
,B r(   c                 *    t         j                  | |dS )z
    Build a success response message dict.

    Args:
        request_id: Request identifier this responds to
        result: Result value

    Returns:
        dict: Response message dict
    )rU   r}   rG   )r   rH   )r   rG   s     r&   make_responser     s     // r(   c                     ddl m} t        ||      r|j                         }n5t        |t              r|}n"t        |      j                  t        |      i d}t        j                  | |dS )z
    Build an error response message dict.

    Args:
        request_id: Request identifier this responds to
        error: DirtyError instance or dict with error info

    Returns:
        dict: Error response message dict
    r   rK   rM   )rU   r}   r   )
rQ   rL   rR   rS   rT   rU   rV   rW   r   rX   )r   r   rL   rY   s       r&   make_error_responser     sf     #%$]]_
	E4	 
 u+..5z

 ,, r(   c                 *    t         j                  | |dS )z
    Build a chunk message dict for streaming responses.

    Args:
        request_id: Request identifier this chunk belongs to
        data: Chunk data

    Returns:
        dict: Chunk message dict
    )rU   r}   r)   )r   r\   )r   r)   s     r&   make_chunk_messager     s     ,, r(   c                 (    t         j                  | dS )z
    Build an end-of-stream message dict.

    Args:
        request_id: Request identifier this ends

    Returns:
        dict: End message dict
    r|   )r   r_   )r   s    r&   make_end_messager     s     ** r(   re   rj   c                 Z    t         j                  | ||d}|||d<   |||d<   |||d<   |S )a  
    Build a stash operation message dict.

    Args:
        request_id: Unique request identifier (int or str)
        op: Stash operation code (STASH_OP_*)
        table: Table name
        key: Optional key for put/get/delete operations
        value: Optional value for put operation
        pattern: Optional pattern for keys operation

    Returns:
        dict: Stash message dict
    )rU   r}   re   rj   rl   rm   rn   )r   ro   )r   re   rj   rl   rm   rn   msgs          r&   make_stash_messager     sP    " ,,	C E
G IJr(   rf   c                 ,    t         j                  | ||dS )a  
    Build a worker management message dict.

    Args:
        request_id: Unique request identifier (int or str)
        op: Management operation (MANAGE_OP_ADD or MANAGE_OP_REMOVE)
        count: Number of workers to add/remove

    Returns:
        dict: Manage message dict
    )rU   r}   re   rf   )r   rh   )r   re   rf   s      r&   make_manage_messager     s      --	 r(   r   r   r   ):r   r   r   r!   rQ   r   tlvr   r$   r%   rA   rH   rX   r\   r_   ro   rc   rh   r   r   r   r   r   r   r   r   r4   itemsr   STASH_OP_PUTSTASH_OP_GETSTASH_OP_DELETESTASH_OP_KEYSSTASH_OP_CLEARSTASH_OP_INFOSTASH_OP_ENSURESTASH_OP_DELETE_TABLESTASH_OP_TABLESSTASH_OP_EXISTSMANAGE_OP_ADDMANAGE_OP_REMOVEr#   calcsizer2   r5   r   r   rW   r   rT   r   r   r   r   r   r   r   r   )kvs   00r&   <module>r      s  
,    &  	
    ! "        *,&&"&((	 '6&;&;&=>daQT>      foom, $ aL aLR 
 59s C -1=A2 $d <D $D " 6:s 3 >B> C  c ?s   $C/