"""将 127.0.0.1 服务地址转为浏览器可访问的外链(内网 IP 或域名)。""" from __future__ import annotations import os from urllib.parse import urlparse, urlunparse _LOCAL_HOSTS = frozenset({"127.0.0.1", "localhost", "::1"}) def public_origin() -> tuple[str, str] | None: """ 从环境变量读取对外 Origin。 HUB_PUBLIC_ORIGIN=http://192.168.1.10 或 HUB_PUBLIC_HOST=192.168.1.10 """ raw = (os.getenv("HUB_PUBLIC_ORIGIN") or os.getenv("HUB_PUBLIC_HOST") or "").strip() if not raw: return None if "://" in raw: p = urlparse(raw) scheme = (p.scheme or "http").strip() host = (p.hostname or "").strip() if not host: return None return scheme, host scheme = (os.getenv("HUB_PUBLIC_SCHEME") or "http").strip() or "http" host = raw.split("/")[0].split(":")[0].strip() return (scheme, host) if host else None def browser_url(internal_url: str | None) -> str: """ 中控本机请求仍用 internal_url;返回给前端、复盘链接用本函数。 若未配置 HUB_PUBLIC_* 或原 URL 已是非本机地址,则原样返回。 """ if not internal_url or not str(internal_url).strip(): return "" u = str(internal_url).strip() origin = public_origin() if not origin: return u scheme_pub, host_pub = origin try: p = urlparse(u) except Exception: return u if not p.scheme or not p.netloc: return u host = (p.hostname or "").lower() if host not in _LOCAL_HOSTS and not host.startswith("::ffff:127.0.0.1"): return u port = p.port netloc = f"{host_pub}:{port}" if port else host_pub return urlunparse((scheme_pub, netloc, p.path or "", p.params, p.query, p.fragment)) def default_review_url(flask_url: str | None) -> str: base = browser_url((flask_url or "").rstrip("/")) if not base: return "" return f"{base}/records"