o
    j1                     @   s   d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	m
Z
 e ZddiZdd Zd	d
 Zdd Zdd ZG dd dZdS )a  
Control Socket Server

Runs in the arbiter process and accepts commands via Unix socket.
Uses asyncio in a background thread to handle client connections.

Fork Safety:
    This server uses os.register_at_fork() to properly handle fork() calls.
    Before fork: the asyncio thread is stopped to prevent lock issues.
    After fork in parent: the server is restarted.
    After fork in child: references are cleared (workers don't need the control server).
    N)CommandHandlers)ControlProtocolmake_responsemake_error_responsefork_handlers_registeredFc                   C   s(   t d rdS dt d< tjtttd dS )z,Register fork handlers once at module level.r   NT)beforeafter_in_parentafter_in_child)_module_stateosregister_at_fork_before_fork_after_fork_parent_after_fork_child r   r   H/var/www/ai-app/venv/lib/python3.10/site-packages/gunicorn/ctl/server.py_register_fork_handlers%   s   
r   c                  C      t tD ]} |   qdS )z7Called before fork() - stop all active control servers.N)list_active_servers_stop_for_forkserverr   r   r   r   2      
r   c                  C   r   )z<Called in parent after fork() - restart all control servers.N)r   r   _restart_after_forkr   r   r   r   r   8   r   r   c                   C   s   t   dS )z2Called in child after fork() - cleanup references.N)r   clearr   r   r   r   r   >   s   r   c                   @   s   e Zd ZdZd$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edefddZdedefddZdedefddZdedefdd Zdedefd!d"Zd#S )%ControlSocketServeraG  
    Control socket server running in arbiter process.

    The server runs an asyncio event loop in a background thread,
    accepting connections and dispatching commands to handlers.

    Fork safety is handled via os.register_at_fork() - the server
    automatically stops before fork and restarts after in the parent.
      c                 C   sD   || _ || _|| _t|| _d| _d| _d| _d| _d| _	t
  dS )z
        Initialize control socket server.

        Args:
            arbiter: The Gunicorn arbiter instance
            socket_path: Path for the Unix socket
            socket_mode: Permission mode for socket (default 0o600)
        NF)arbitersocket_pathsocket_moder   handlers_server_loop_thread_running_was_running_before_forkr   )selfr   r   r    r   r   r   __init__P   s   	

zControlSocketServer.__init__c                 C   s:   | j rdS d| _ tj| jdd| _| j  t|  dS )z:Start server in background thread with asyncio event loop.NTtargetdaemon)r%   	threadingThread	_run_loopr$   startr   addr'   r   r   r   r/   g   s   
zControlSocketServer.startc                 C   s   t |  | js
dS d| _| jr| jr| j| j | jr'| jjdd d| _t	j
| jrBz	t	| j W dS  tyA   Y dS w dS )zStop server and cleanup socket.NF       @timeout)r   discardr%   r#   r"   call_soon_threadsafe	_shutdownr$   joinr   pathexistsr   unlinkOSErrorr1   r   r   r   stops   s    
zControlSocketServer.stopc                 C   sx   | j sd| _dS d| _d| _ | jr'| jr'z	| j| j W n	 ty&   Y nw | jr4| jjdd d| _d| _d| _dS )z1Stop server before fork (called by fork handler).FNTr2   r3   )	r%   r&   r#   r"   r6   r7   RuntimeErrorr$   r8   r1   r   r   r   r      s    
z"ControlSocketServer._stop_for_forkc                 C   s6   | j sdS d| _ d| _tj| jdd| _| j  dS )z=Restart server in parent after fork (called by fork handler).NFTr)   )r&   r%   r,   r-   r.   r$   r/   r1   r   r   r   r      s   z'ControlSocketServer._restart_after_forkc                 C   s   | j r
| j   dS dS )z0Shutdown server (called from event loop thread).N)r"   closer1   r   r   r   r7      s   zControlSocketServer._shutdownc              
   C   sv   z
t |   W dS  ty: } z$| jr(| jjr/| jjd| W Y d}~dS W Y d}~dS W Y d}~dS d}~ww )z0Run the asyncio event loop in background thread.zControl server error: %sN)asynciorun_serve	Exceptionr%   r   logerror)r'   er   r   r   r.      s   zControlSocketServer._run_loopc                    sl  t  | _tj| j}|rtj|stj|dd tj| jr)t	| j t j
| j| jdI dH | _t| j| j | jjrK| jjd| j zPz'| j4 I dH  | j I dH  W d  I dH  n1 I dH smw   Y  W n
 t jy}   Y nw W tj| jrz	t	| j W dS  ty   Y dS w dS tj| jrzt	| j W w  ty   Y w w w )zMain async server loop.i  )mode)r9   NzControl socket listening at %s)r@   get_running_loopr#   r   r9   dirnamer   r:   makedirsr;   start_unix_server_handle_clientr"   chmodr    r   rD   infoserve_foreverCancelledErrorr<   )r'   
socket_dirr   r   r   rB      sL   

(zControlSocketServer._servec                    s,  z}zD| j rEztjt|ddI dH }W n tjy   Y n& tjy(   Y n ty0   Y nw | |I dH }t	||I dH  | j sW n tyd } z| j
jrZ| j
jd| W Y d}~nd}~ww W |  z
| I dH  W dS  ty~   Y dS w |  z	| I dH  W w  ty   Y w w )z
        Handle client connection.

        Args:
            reader: asyncio StreamReader
            writer: asyncio StreamWriter
        g     r@r3   NzControl client error: %s)r%   r@   wait_forr   read_message_asyncTimeoutErrorIncompleteReadErrorrC   	_dispatchwrite_message_asyncr   rD   debugr?   wait_closed)r'   readerwritermessageresponserF   r   r   r   rL      sJ   z"ControlSocketServer._handle_clientr\   returnc              
      s   | dd}| dd }| dg }|st|dS z$t|}|r.|dd |D  |s6t|dW S | |}t||W S  tyZ } zt|d	| W  Y d
}~S d
}~w t	y~ } z| j
jrl| j
jd t|d| W  Y d
}~S d
}~ww )z
        Dispatch command to appropriate handler.

        Args:
            message: Request message dict

        Returns:
            Response dictionary
        idr   command argsEmpty commandc                 s   s    | ]}t |V  qd S )N)str).0ar   r   r   	<genexpr>  s    z0ControlSocketServer._dispatch.<locals>.<genexpr>zInvalid argument: NzCommand errorzCommand failed: )getstripr   shlexsplitextend_execute_commandr   
ValueErrorrC   r   rD   	exception)r'   r\   
request_idr`   rb   partsresultrF   r   r   r   rV   	  s.   



zControlSocketServer._dispatchrq   c                 C   s   |st d|d  }|dd }|dkr| |S |dkr$| |S |dkr-| |S |dkr6| j S |d	kr?| j S |d
krQ|rI|d nd}| j|S |dkrZ| j	 S t d| )z
        Execute a parsed command.

        Args:
            parts: Command parts (e.g., ["show", "workers"])

        Returns:
            Handler result dictionary
        rc   r      NshowworkerdirtyreloadreopenshutdowngracefulhelpzUnknown command: )
rn   lower_handle_show_handle_worker_handle_dirtyr!   rw   rx   ry   r{   )r'   rq   cmdrestrG   r   r   r   rm   .  s(   






z$ControlSocketServer._execute_commandrb   c                 C   s   |st d|d  }|dkr| j S |dkr| j S |dkr'| j S |dkr0| j S |dkr9| j S |dkrB| j S t d	| )
zHandle 'show' commands.z>Missing show target (all|workers|dirty|config|stats|listeners)r   allworkersrv   configstats	listenerszUnknown show target: )	rn   r|   r!   show_allshow_workers
show_dirtyshow_config
show_statsshow_listeners)r'   rb   r*   r   r   r   r}   Q  s    





z ControlSocketServer._handle_showc                 C   s   |st d|d  }|dd }|dkr&|rt|d nd}| j|S |dkr:|r2t|d nd}| j|S |dkrP|sDt dt|d }| j|S t d	| )
zHandle 'worker' commands.z'Missing worker action (add|remove|kill)r   rs   Nr0   removekillzMissing PID for worker killzUnknown worker action: )rn   r|   intr!   
worker_addworker_removeworker_kill)r'   rb   actionaction_argscountpidr   r   r   r~   g  s    z"ControlSocketServer._handle_workerc                 C   s   |st d|d  }|dd }|dkr&|rt|d nd}| j|S |dkr:|r2t|d nd}| j|S t d| )zHandle 'dirty' commands.z!Missing dirty action (add|remove)r   rs   Nr0   r   zUnknown dirty action: )rn   r|   r   r!   	dirty_adddirty_remove)r'   rb   r   r   r   r   r   r   r   }  s   z!ControlSocketServer._handle_dirtyN)r   )__name__
__module____qualname____doc__r(   r/   r=   r   r   r7   r.   rB   rL   dictrV   r   rm   r}   r~   r   r   r   r   r   r   E   s     


&)%#r   )r   r@   r   rj   r,   gunicorn.ctl.handlersr   gunicorn.ctl.protocolr   r   r   setr   r
   r   r   r   r   r   r   r   r   r   <module>   s   	