o
    `۷i(                     @   s   d dl Z d dlmZmZmZmZmZmZ d dlm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZmZmZ d dlmZ d d	lmZmZ d d
lmZ e eZdZdZG dd dZdS )    N)AnyCallableDictListOptionalTuple)	Starlette)Request)Route)Scope)ApplicationNameDeploymentIDEndpointInfo)SERVE_LOGGER_NAME)RoutePatternget_asgi_route_name)DeploymentHandlez!Route table is not populated yet.zNo replicas are available yet.c                   @   s   e Zd ZdZdeeegef fddZdede	eef fddZ
d	eeef fd
dZdedee	eeef  fddZdedee	eeef  fddZdededefddZdS )ProxyRouterz&Router interface for the proxy to use.
get_handlec                 C   sH   || _ t | _d| _t | _t | _t | _t | _t | _	t | _
d S )NF)_get_handledicthandles_route_table_populatedlistsorted_routes
route_infoapp_to_is_cross_language	endpointsroute_patterns_route_pattern_apps)selfr    r!   U/home/ubuntu/vllm_env/lib/python3.10/site-packages/ray/serve/_private/proxy_router.py__init__   s   zProxyRouter.__init__is_headreturnc                 C   s<   | j sdtfS |rdS | j D ]	}| r dS qdtfS )a  Whether the proxy router is ready to serve traffic.

        The first return value will be false if any of the following hold:
        - The route table has not been populated yet with a non-empty set of routes
        - The route table has been populated, but none of the handles
          have received running replicas yet AND it lives on a worker node.

        Otherwise, the first return value will be true.
        F)T )r   NO_ROUTES_MESSAGEr   valuesrunning_replicas_populatedNO_REPLICAS_MESSAGE)r    r$   handler!   r!   r"   ready_for_traffic:   s   zProxyRouter.ready_for_trafficr   c           	      C   s&  t jd| dddid |rd| _|| _t| j }g }i }i }i }| D ]2\}}||j	 |||j	< |j
||j< |jrF|j||j	< || jv rQ|| q(| ||| j|< q(t|dkrpt jdt| ddd	id |D ]}| j|= qrt|d
d dd| _|| _|| _|| _| j  d S )NzGot updated endpoints: .log_to_stderrT)extrar   z	Deleting z unused handles.Fc                 S   s   t | S N)len)xr!   r!   r"   <lambda>{   s    z+ProxyRouter.update_routes.<locals>.<lambda>)keyreverse)loggerinfor   r   setr   keysitemsappendrouteapp_is_cross_languageapp_namer   remover   r1   sortedr   r   r   r   clear)	r    r   existing_handlesroutesr   r   r   endpointr7   r!   r!   r"   update_routesW   s@   


zProxyRouter.update_routestarget_routec                 C   s|   | j D ]8}||r;d}|drd}nt|t|ks$|t| dkr&d}|r;| j| }|| j| | j|j f  S qdS )zReturn the longest prefix match among existing routes for the route.
        Args:
            target_route: route to match against.
        Returns:
            (route, handle, is_cross_language) if found, else None.
        F/TN)r   
startswithendswithr1   r   r   r   r>   )r    rF   r<   matchedrD   r!   r!   r"   match_route   s   



 

zProxyRouter.match_routetarget_app_namec                 C   sL   | j  D ]\}}||jkst| j dkr#| j| }|j||jf  S qdS )a2  Return the handle that matches with endpoint.

        Args:
            target_app_name: app_name to match against.
        Returns:
            (route, handle, is_cross_language) for the single app if there
            is only one, else find the app and handle for exact match. Else return None.
           N)r   r:   r>   r1   r   r<   r=   )r    rL   endpoint_tagr+   endpoint_infor!   r!   r"   get_handle_for_endpoint   s   
z#ProxyRouter.get_handle_for_endpointroute_prefix
asgi_scopec                    s   || j vr|S | j | }|s|S | j|}|du rLzdtfdd  fdd|D }t|d}|| j|< W n tyK   tjd| d	d
 | Y S w zt||}|rW|W S W |S  tym   tjd| d	d
 Y |S w )a  Match an incoming request to a specific route pattern.

        This attempts to match the request path to a route pattern (e.g., /api/{user_id})
        rather than just the route prefix. This provides more granular metrics.

        The mock Starlette app is cached per route_prefix for performance, avoiding
        the overhead of recreating the app and routes on every request.

        Args:
            route_prefix: The matched route prefix from match_route()
            asgi_scope: The ASGI scope containing the request path and method

        Returns:
            The matched route pattern if available, otherwise the route_prefix
        Nrequestc                    s   d S r0   r!   )rS   r!   r!   r"   dummy_endpoint   s   z7ProxyRouter.match_route_pattern.<locals>.dummy_endpointc                    s   g | ]}t |j |jd qS ))methods)r
   pathrU   ).0patternrT   r!   r"   
<listcomp>   s    z3ProxyRouter.match_route_pattern.<locals>.<listcomp>)rC   z6Failed to create mock app for route pattern matching: T)exc_infoz"Failed to match route pattern for )	r   r   getr	   r   	Exceptionr6   debugr   )r    rQ   rR   patternsmock_apprC   rJ   r!   rY   r"   match_route_pattern   sD   



	

zProxyRouter.match_route_patternN)__name__
__module____qualname____doc__r   strr   r#   boolr   r,   r   r   r   rE   r   rK   rP   r   ra   r!   r!   r!   r"   r      s$    
 +
$
r   ) loggingtypingr   r   r   r   r   r   starlette.applicationsr   starlette.requestsr	   starlette.routingr
   starlette.typesr   ray.serve._private.commonr   r   r   ray.serve._private.constantsr   1ray.serve._private.thirdparty.get_asgi_route_namer   r   ray.serve.handler   	getLoggerr6   r'   r*   r   r!   r!   r!   r"   <module>   s     
