
     ia                         S r SSKrSSKrSSKrSSKJr  SSKJr  SrSr	Sr
SrSrS	rS
rSrSrSrSrSrSrSrSrSrSrSr\
\\\\\\\\\\\\\\\0r\R7                  5        V Vs0 s H  u  pX_M	     snn rSrSrSrS	r S
r!Sr"Sr#Sr$Sr%Sr&Sr'Sr(Sr)\RT                  " \)5      r+Sr, " S S5      r-\-r. S.S\/S \/S!\0S"\1S#\14
S$ jjr2S#\14S% jr3S#\14S& jr4S#\14S' jr5S#\14S( jr6 S/S)\7S*\/S#\14S+ jjr8S0S)\7S,\7S#\14S- jjr9gs  snn f )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                      \ rS rSrSr\r\r\r\	r
\r\r\r\r\r\r\S\S\S\S\4S j5       r\S\S\4S	 j5       r\ S'S\S\S\S\S\S\4S jj5       r\S\S\4S j5       r \S\S\4S j5       r!\S\S\4S j5       r"\S\S\4S j5       r#\S\S\4S j5       r$\S(S\S\S\S\4S jj5       r%\ S)S\S\S\S\4S jj5       r&\S\S\4S j5       r'\S\(RR                  S\4S j5       r*\S\(RV                  S\SS
4S j5       r,\S \-RZ                  S!\S\4S" j5       r.\S \-RZ                  S\4S# j5       r/\S \-RZ                  S\SS
4S$ j5       r0\S\S\4S% j5       r1S&r2g
)*BinaryProtocolb   z-Binary message protocol for dirty worker IPC.msg_type
request_idpayload_lengthreturnc                 N    [         R                  " [        [        [        U X!5      $ )z
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      I/var/www/ias/venv/lib/python3.13/site-packages/gunicorn/dirty/protocol.pyencode_headerBinaryProtocol.encode_headerr   s      {{=%()7 	7    datac                    [        U 5      [        :  a  [        S[        U 5       S[         3U S9e[        R                  " [
        U S[         5      u  pp4nU[        :w  a  [        SU< S[        < 3U SS S9eU[        :w  a  [        SU S[         3U SS S9eU[        ;  a  [        S	US
 3U SS S9eU[        :  a  [        SU S[         S35      eX5U4$ )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_headerBinaryProtocol.decode_header   s    t9{"$$SYK/@N 
 8>}}4-8
4* E>$!%+eY?cr 
 g$0	WINcr 
 ?*$*8C.9cr 
 $$$%fX];K:LAN  V++r*   Napp_pathactionargskwargsc                     UUU(       a  [        U5      O/ U=(       d    0 S.n[        R                  " U5      n[        R	                  [
        U [        U5      5      nXv-   $ )a  
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_REQUESTr3   )r   r=   r>   r?   r@   payload_dictpayloadheaders           r'   encode_requestBinaryProtocol.encode_request   sZ    " !"&DJBl	
 ##L1--.>
.1'l<r*   c                     SU0n[         R                  " U5      n[        R                  [        U [        U5      5      nXC-   $ )z
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   rC   r   r(   MSG_TYPE_RESPONSEr3   )r   rK   rE   rF   rG   s        r'   encode_responseBinaryProtocol.encode_response   sC     !&)##L1--.?.1'l<r*   c                 H   SSK Jn  [        X5      (       a  UR                  5       nO:[        U[        5      (       a  UnO"[        U5      R                  [        U5      0 S.nSU0n[        R                  " U5      n[        R                  [        U [        U5      5      nXe-   $ )z
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   )errorsrQ   
isinstanceto_dictdicttype__name__strr   rC   r   r(   MSG_TYPE_ERRORr3   )r   r   rQ   
error_dictrE   rF   rG   s          r'   encode_errorBinaryProtocol.encode_error   s     	'e((Jt$$J #5k22u:J  ,##L1--nj.1'l<r*   c                     SU0n[         R                  " U5      n[        R                  [        U [        U5      5      nXC-   $ )z
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   rC   r   r(   MSG_TYPE_CHUNKr3   )r   r+   rE   rF   rG   s        r'   encode_chunkBinaryProtocol.encode_chunk   sA     ~##L1--nj.1'l<r*   c                 <    [         R                  [        U S5      nU$ )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   rG   s     r'   
encode_endBinaryProtocol.encode_end  s      --lJJr*   c                 <    [         R                  [        U S5      nU$ )z
Encode a status query message.

Args:
    request_id: Request identifier

Returns:
    bytes: Complete message (header + empty payload)
r   )r   r(   MSG_TYPE_STATUSrg   s     r'   encode_statusBinaryProtocol.encode_status   s      --oz1Mr*   opcountc                     UUS.n[         R                  " U5      n[        R                  [        U [        U5      5      nXT-   $ )z
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)
)rn   ro   )r   rC   r   r(   MSG_TYPE_MANAGEr3   )r   rn   ro   rE   rF   rG   s         r'   encode_manageBinaryProtocol.encode_manage/  sG     
 ##L1--oz.1'l<r*   tablec                     UUS.nUb  X6S'   Ub  XFS'   Ub  XVS'   [         R                  " U5      n[        R                  [        U [        U5      5      nX-   $ )ag  
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)
)rn   rt   keyvaluepattern)r   rC   r   r(   MSG_TYPE_STASHr3   )	r   rn   rt   rv   rw   rx   rE   rF   rG   s	            r'   encode_stashBinaryProtocol.encode_stashE  sp    $ 
 ?"%$)!&-###L1--nj.1'l<r*   c                 v   [         R                  U 5      u  pn[        U 5      [        U-   :  a#  [	        S[        U-    S[        U 5       3U SS S9eUS:X  a  0 nO'U [        [        U-    n [
        R                  " U5      n[        U   nXrU4$ ! [         a    e [         a  n[	        SU 3USS S9eSnAff = f)aH  
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   r;   r3   r4   r   r   decode_full	Exceptionr6   )r+   r   r   r:   rE   payload_dataemsg_type_strs           r'   decode_message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55 &  (4QC8)#2. s   ,B B8#B33B8readerc                   #     U R                  [        5      I Sh  vN n[        R                  U5      u  p4nUS:  a2   U R                  U5      I Sh  vN n [        R                  " U5      nO0 n[        U   nXS	.n	U	R                  U5        U	$  Nv! [        R                   aP  n[	        UR
                  5      S:X  a  e [        S[	        UR
                  5       S[         3UR
                  S9eSnAff = f N! [        R                   a2  n[        S[	        UR
                  5       SU 3UR
                  S9eSnAff = f! [         a    e [         a  n[        SU 3USS S9eSnAff = f7f)
a(  
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 r~   r}   rZ   id)readexactlyr4   asyncioIncompleteReadErrorr3   partialr   r   r;   r   r   r   r6   update)
r   rG   r   r   r   r:   r   rE   r   rK   s
             r'   read_message_async!BinaryProtocol.read_message_async  s     
	!--k::F (6'C'CF'K$f A:%+%7%7%??)55lC L 'x0&9l#S ;** 	199~"$)#aii.)9 :'=* 		  @.. (.s199~.> ?  &x)YY  &  (4QC8)#2. s   E3B BB E3 C> C<C> E 0#E3B C9)AC44C99E3<C> >E-D??EE3E0E++E00E3writerrT   c                    #    [         R                  U5      nU R                  U5        U R                  5       I Sh  vN   g N7f)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   rT   r+   s      r'   write_message_async"BinaryProtocol.write_message_async  s2       //8Tllns   :AAAsocknc                     Sn[        U5      U:  al  U R                  U[        U5      -
  5      nU(       d3  [        U5      S:X  a  [        S5      e[        S[        U5       SU 3US9eX#-  n[        U5      U:  a  Ml  U$ )z
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.   )r3   recvr   )r   r   r+   r   s       r'   _recv_exactlyBinaryProtocol._recv_exactly  s     $i!mIIa#d)m,Et9>,-@AA(.s4yk9J1#N!  MD $i!m r*   c                 h   [         R                  U [        5      n[         R                  U5      u  p#nUS:  a-  [         R                  X5      n [        R
                  " U5      nO0 n[        U   nXS.n	U	R                  U5        U	$ ! [         a    e [         a  n[        SU 3USS S9eSnAff = f)z
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   r~   Nr}   r.   r   )
r   r   r4   r;   r   r   r   r   r6   r   )
r   rG   r   r   r:   r   rE   r   r   rK   s
             r'   read_messageBinaryProtocol.read_message  s      --dK@'5'C'CF'K$f A:)77EL)55lC L 'x0&9l# &  (4QC8)#2. s   B B1B,,B1c                 P    [         R                  U5      nU R                  U5        g)z
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   rT   r+   s      r'   write_messageBinaryProtocol.write_message/  s      //8Tr*   c           
         U R                  S5      nU R                  SS5      n[        U[        5      (       a  [        U5      S-  n[        R                  U5      nUc  [        SU 35      eU[        :X  aW  [        R                  UU R                  SS5      U R                  SS5      U R                  S	5      U R                  S
5      5      $ U[        :X  a%  [        R                  UU R                  S5      5      $ U[        :X  a&  [        R                  UU R                  S0 5      5      $ U[        :X  a%  [        R                  UU R                  S5      5      $ U[        :X  a  [        R!                  U5      $ U["        :X  af  [        R%                  UU R                  S5      U R                  SS5      U R                  S5      U R                  S5      U R                  S5      5      $ U[&        :X  a  [        R)                  U5      $ U[*        :X  a6  [        R-                  UU R                  S5      U R                  SS5      5      $ [        SU 35      e)z
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
rZ   r   r   l    zUnknown message type: r=    r>   r?   r@   rK   r   r+   rn   rt   rv   rw   rx   ro   r   zUnhandled message type: )getrW   r\   hashMSG_TYPE_FROM_STRr   rD   r   rH   rL   rM   r]   r_   rb   rc   rf   rh   ry   rz   rk   rl   rq   rr   )rT   r   r   r   s       r'   r    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)3r[   
__module____qualname____firstlineno____doc__r4   r7   MSG_TYPE_REQUEST_STRrD   MSG_TYPE_RESPONSE_STRrL   MSG_TYPE_ERROR_STRr]   MSG_TYPE_CHUNK_STRrb   MSG_TYPE_END_STRrf   MSG_TYPE_STASH_STRry   MSG_TYPE_STATUS_STRrk   MSG_TYPE_MANAGE_STRrq   staticmethodintbytesr(   tupler;   r\   rY   rH   rM   r_   rc   rh   rl   rr   rz   r   r   StreamReaderr   StreamWriterr   socketr   r   r   r   __static_attributes__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                 f    [         R                  U UUU(       a  [        U5      O/ U=(       d    0 S.$ )a-  
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
)rZ   r   r=   r>   r?   r@   )DirtyProtocolrD   rB   )r   r=   r>   r?   r@   s        r'   make_requestr     s2      .."T
,B r*   c                 *    [         R                  U US.$ )z
Build a success response message dict.

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

Returns:
    dict: Response message dict
)rZ   r   rK   )r   rL   )r   rK   s     r'   make_responser     s     // r*   c                     SSK Jn  [        X5      (       a  UR                  5       nO:[        U[        5      (       a  UnO"[        U5      R                  [        U5      0 S.n[        R                  U U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   rP   rR   )rZ   r   r   )
rV   rQ   rW   rX   rY   rZ   r[   r\   r   r]   )r   r   rQ   r^   s       r'   make_error_responser     sj     #%$$]]_
	E4	 	 
 u+..5z

 ,, r*   c                 *    [         R                  U U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
)rZ   r   r+   )r   rb   )r   r+   s     r'   make_chunk_messager     s     ,, r*   c                 (    [         R                  U S.$ )z
Build an end-of-stream message dict.

Args:
    request_id: Request identifier this ends

Returns:
    dict: End message dict
r   )r   rf   )r   s    r'   make_end_messager     s     ** r*   rn   rt   c                 Z    [         R                  U UUS.nUb  X6S'   Ub  XFS'   Ub  XVS'   U$ )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
)rZ   r   rn   rt   rv   rw   rx   )r   ry   )r   rn   rt   rv   rw   rx   msgs          r'   make_stash_messager     sJ    " ,,	C E
G IJr*   ro   c                 ,    [         R                  U UUS.$ )z
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
)rZ   r   rn   ro   )r   rq   )r   rn   ro   s      r'   make_manage_messager     s      --	 r*   r   r   r   ):r   r   r   r"   rV   r   tlvr   r%   r&   rD   rL   r]   rb   rf   ry   rk   rq   r   r   r   r   r   r   r   r   r6   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$   calcsizer4   r7   r   r   r\   r   rY   r   r   r   r   r   r   r   r   )kvs   00r'   <module>r      s  
,    &  	
    ! "        *,&&"&((	 '6&;&;&=>&=daQT&=>      oom, $ aL aLR 
 59s C -1=A2 $d <D $D " 6:s 3 >B> C  c ?s   $C: