o
    iI                  	   @   s   d Z ddlZddlZG dd deZG dd dZddeded	ed
e	fddZ
ddede	d
e	fddZdeded
e	fddZdS )a  
Control Socket Protocol

JSON-based protocol with length-prefixed framing for the control interface.

Message Format:
    +----------------+------------------+
    | Length (4B BE) |  JSON Payload    |
    +----------------+------------------+

Request Format:
    {"id": 1, "command": "show", "args": ["workers"]}

Response Format:
    {"id": 1, "status": "ok", "data": {...}}
    {"id": 1, "status": "error", "error": "message"}
    Nc                   @   s   e Zd ZdZdS )ProtocolErrorzProtocol-level error.N)__name__
__module____qualname____doc__ r   r   I/home/ubuntu/.local/lib/python3.10/site-packages/gunicorn/ctl/protocol.pyr      s    r   c                   @   s   e Zd ZdZdZededefddZededefddZ	edefd	d
Z
edefddZedefddZedefddZdS )ControlProtocolz
    Protocol implementation for control socket communication.

    Uses 4-byte big-endian length prefix followed by JSON payload.
    i   datareturnc                 C   s(   t | d}tdt|}|| S )z
        Encode a message for transmission.

        Args:
            data: Dictionary to encode

        Returns:
            Length-prefixed JSON bytes
        utf-8>I)jsondumpsencodestructpacklen)r
   payloadlengthr   r   r   encode_message)   s   zControlProtocol.encode_messagec                 C   sd   t | dk r
tdtd| dd d }t | d| k r"td| dd|  }t|dS )z
        Decode a message from bytes.

        Args:
            data: Raw bytes (length prefix + JSON payload)

        Returns:
            Decoded dictionary
           zMessage too shortr   Nr   zIncomplete messager   )r   r   r   unpackr   loadsdecode)r
   r   r   r   r   r   decode_message8   s   zControlProtocol.decode_messagec              
   C   s   d}t |dk r'| dt | }|s|stdtd||7 }t |dk std|d }|tjkr;td| d}t ||k r_| t|t | d}|sUtd	||7 }t ||k sCz	t	
|d
W S  t	jy| } ztd| d}~ww )a  
        Read one message from a socket.

        Args:
            sock: Socket to read from

        Returns:
            Decoded message dictionary

        Raises:
            ProtocolError: If message is malformed
            ConnectionError: If connection is closed
            r   zConnection closedzIncomplete length prefixr   r   Message too large: i   zIncomplete payloadr   Invalid JSON: N)r   recvConnectionErrorr   r   r   r	   MAX_MESSAGE_SIZEminr   r   r   JSONDecodeError)socklength_datachunkr   payload_dataer   r   r   read_messageM   s2   
zControlProtocol.read_messagec                 C   s   t |}| | dS )z
        Write one message to a socket.

        Args:
            sock: Socket to write to
            data: Message dictionary to send
        N)r	   r   sendall)r$   r
   messager   r   r   write_messagex   s   
	zControlProtocol.write_messagec              
      s   |  dI dH }td|d }|tjkrtd| |  |I dH }z	t|dW S  tj	yB } ztd| d}~ww )z
        Read one message from an async reader.

        Args:
            reader: asyncio StreamReader

        Returns:
            Decoded message dictionary
        r   Nr   r   r   r   r   )
readexactlyr   r   r	   r!   r   r   r   r   r#   )readerr%   r   r'   r(   r   r   r   read_message_async   s   
z"ControlProtocol.read_message_asyncc                    s(   t |}| | |  I dH  dS )z
        Write one message to an async writer.

        Args:
            writer: asyncio StreamWriter
            data: Message dictionary to send
        N)r	   r   writedrain)writerr
   r+   r   r   r   write_message_async   s   
	
z#ControlProtocol.write_message_asyncN)r   r   r   r   r!   staticmethoddictbytesr   r   r)   r,   r/   r3   r   r   r   r   r	      s    *r	   
request_idcommandargsr   c                 C   s   | ||pg dS )z
    Create a request message.

    Args:
        request_id: Unique request identifier
        command: Command name (e.g., "show workers")
        args: Optional list of arguments

    Returns:
        Request dictionary
    )idr8   r9   r   )r7   r8   r9   r   r   r   make_request   s   r;   r
   c                 C   s   | d|pi dS )z
    Create a success response message.

    Args:
        request_id: Request identifier being responded to
        data: Response data

    Returns:
        Response dictionary
    ok)r:   statusr
   r   )r7   r
   r   r   r   make_response   s   r>   errorc                 C   s   | d|dS )z
    Create an error response message.

    Args:
        request_id: Request identifier being responded to
        error: Error message

    Returns:
        Error response dictionary
    r?   )r:   r=   r?   r   )r7   r?   r   r   r   make_error_response   s   r@   )N)r   r   r   	Exceptionr   r	   intstrlistr5   r;   r>   r@   r   r   r   r   <module>   s    