"""Server-owned request provenance, inherited by async output-recording tasks.""" from contextvars import ContextVar from typing import Awaitable, Callable from fastapi import Request, Response from fastapi.routing import APIRoute CLIENT_SOURCES = frozenset({'android', 'wechat', 'ios', 'web', 'unknown'}) current_client_source: ContextVar[str] = ContextVar('client_source', default='unknown') def validate_client_source(source: str) -> str: if source not in CLIENT_SOURCES: raise ValueError('Unsupported client source') return source def resolve_client_source(request: Request) -> str: """Explicit routes win; legacy shared Android routes carry x-device-id.""" path = request.url.path.rstrip('/') for prefix, source in (('/facescore/app/', 'android'), ('/facescore/wechat/', 'wechat'), ('/facescore/ios/', 'ios'), ('/facescore/web/', 'web')): if path.startswith(prefix): return source # Original analyze is the mini-program entry; app/analyze delegates internally. if path == '/facescore/analyze': return 'wechat' if path.startswith('/facescore/'): return 'android' if request.headers.get('x-device-id', '').strip() else 'wechat' return 'unknown' class ClientSourceRoute(APIRoute): def get_route_handler(self) -> Callable[[Request], Awaitable[Response]]: original_handler = super().get_route_handler() async def handle(request: Request) -> Response: token = current_client_source.set(resolve_client_source(request)) try: return await original_handler(request) finally: current_client_source.reset(token) return handle