优化网络与系统检测为缓存优先,避免页面长时间停留在检测中。

将网络/IP 路由拆分并加入去重缓存,系统检测改为线程执行并支持强制刷新,前端改为先展示缓存快照后按需手动重测,降低阻塞与重复探测开销。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
eric
2026-07-08 14:38:59 -05:00
parent 1287b72193
commit 0661c33610
7 changed files with 375 additions and 126 deletions

61
web2.py
View File

@@ -19,9 +19,7 @@ from web2_supervisor import (
strip_ansi_codes,
use_builtin,
)
from web2_network import run_network_dashboard
from web2_ip_profile import run_ip_profile
from web2_ip_quality import run_ip_quality
from web2_network_routes import router as network_router
from web2_proxy_config import read_proxy_config, write_proxy_config
from web2_system_metrics import snapshot as system_metrics_snapshot
from web2_youtube_oauth import (
@@ -100,6 +98,9 @@ CONFIG_DIR = BASE_DIR / "config"
DEFAULT_LOG_DIR = BASE_DIR / ".pm2" / "logs"
RELAY_DB = relay_db_path(BASE_DIR)
_PROCESS_STATUS_CACHE: dict[str, str] = {}
_SYSTEM_METRICS_TTL_SECONDS = 10.0
_SYSTEM_METRICS_CACHE: tuple[float, dict] | None = None
_SYSTEM_METRICS_CACHE_LOCK = asyncio.Lock()
MAX_LOG_LINES = 300
@@ -302,6 +303,7 @@ app.add_middleware(
allow_methods=["GET", "POST", "OPTIONS"],
allow_headers=["*"],
)
app.include_router(network_router)
@app.get("/client/overview")
async def client_overview():
@@ -1095,40 +1097,6 @@ async def health():
return {"ok": True}
@app.get("/network_status")
async def network_status():
"""Google / 抖音 连通与简易网速(供仪表盘)。"""
try:
return await run_network_dashboard()
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/ip_profile")
async def ip_profile(
tz: str = Query("", description="客户端 IANA 时区,如 Asia/Shanghai"),
lang: str = Query("", description="客户端语言,如 zh-CN"),
webrtc_leak: Optional[str] = Query(None, description="1/true 表示检测到 WebRTC 本地泄露"),
):
"""静态住宅 IP / 出口画像(参考 whoer、ping0.cc"""
leak_flag: Optional[bool] = None
if webrtc_leak is not None:
leak_flag = str(webrtc_leak).strip().lower() in ("1", "true", "yes")
try:
return await run_ip_profile(client_tz=tz.strip(), client_lang=lang.strip(), webrtc_leak=leak_flag)
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/ip_quality")
async def ip_quality():
"""IP 质量检测(集成 xykt/IPQuality 数据源与流媒体解锁)。"""
try:
return await run_ip_quality()
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/proxy_config")
async def get_proxy_config():
"""仅作用于录制子进程的代理(不写 Windows 系统代理)。"""
@@ -1154,10 +1122,25 @@ async def post_proxy_config(request: Request):
@app.get("/system_metrics")
async def system_metrics():
async def system_metrics(
force_refresh: bool = Query(False, description="是否跳过缓存强制重新检测"),
):
"""CPU/内存/磁盘/网卡速率与 ffmpeg 进程摘要。"""
global _SYSTEM_METRICS_CACHE
try:
return system_metrics_snapshot()
now = time.time()
async with _SYSTEM_METRICS_CACHE_LOCK:
if (
not force_refresh
and _SYSTEM_METRICS_CACHE
and (now - _SYSTEM_METRICS_CACHE[0]) < _SYSTEM_METRICS_TTL_SECONDS
):
return _SYSTEM_METRICS_CACHE[1]
payload = await asyncio.to_thread(system_metrics_snapshot)
async with _SYSTEM_METRICS_CACHE_LOCK:
_SYSTEM_METRICS_CACHE = (time.time(), payload)
return payload
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)