优化直播控制台:引入进程监控轻量轮询,并拆分 Live UI 组件
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
@@ -26,6 +27,37 @@ def strip_ansi_codes(text: str) -> str:
|
||||
return re.sub(r"\x1b\[[0-9;]*m", "", text)
|
||||
|
||||
|
||||
def _looks_like_null_device(path: str | Path | None) -> bool:
|
||||
if not path:
|
||||
return True
|
||||
norm = str(path).replace("\\", "/").lower()
|
||||
return "/dev/null" in norm or norm.endswith("/nul") or norm == "nul"
|
||||
|
||||
|
||||
def _truncate_text_log(path: str | Path | None) -> None:
|
||||
"""对齐 sh2:每次 start 清空日志,避免旧 mtime 触发 stale/心跳过期。"""
|
||||
if _looks_like_null_device(path):
|
||||
return
|
||||
log_path = Path(str(path))
|
||||
try:
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with log_path.open("w", encoding="utf-8", errors="ignore"):
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def _child_env_for_process(process_name: str) -> dict[str, str]:
|
||||
extra: dict[str, str] = {
|
||||
"LIVE_PM2_PROCESS_NAME": process_name,
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
"PYTHONIOENCODING": "utf-8",
|
||||
}
|
||||
if process_name.startswith("youtube2__"):
|
||||
extra["RELAY_CHANNEL_ID"] = process_name[len("youtube2__") :]
|
||||
return merge_child_env(extra)
|
||||
|
||||
|
||||
class BuiltinSupervisor:
|
||||
"""用本地 PID + 日志文件管理子进程,不依赖 Node/PM2。"""
|
||||
|
||||
@@ -107,11 +139,10 @@ class BuiltinSupervisor:
|
||||
|
||||
out_p, err_p = self._log_paths(process_name)
|
||||
out_p.parent.mkdir(parents=True, exist_ok=True)
|
||||
out_f = open(out_p, "ab")
|
||||
err_f = open(err_p, "ab")
|
||||
extra: dict[str, str] = {}
|
||||
if process_name.startswith("youtube2__"):
|
||||
extra["RELAY_CHANNEL_ID"] = process_name[len("youtube2__") :]
|
||||
_truncate_text_log(out_p)
|
||||
_truncate_text_log(err_p)
|
||||
out_f = open(out_p, "a", encoding="utf-8", errors="ignore")
|
||||
err_f = open(err_p, "a", encoding="utf-8", errors="ignore")
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*argv,
|
||||
@@ -119,7 +150,7 @@ class BuiltinSupervisor:
|
||||
stdout=out_f,
|
||||
stderr=err_f,
|
||||
creationflags=0,
|
||||
env=merge_child_env(extra),
|
||||
env=_child_env_for_process(process_name),
|
||||
)
|
||||
except Exception as e:
|
||||
out_f.close()
|
||||
@@ -134,6 +165,7 @@ class BuiltinSupervisor:
|
||||
"script": script,
|
||||
"out_log": str(out_p),
|
||||
"err_log": str(err_p),
|
||||
"started_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
|
||||
}
|
||||
self._write_state(state)
|
||||
return f"已启动 {script}(PID {pid}),日志见 .pm2/logs"
|
||||
|
||||
Reference in New Issue
Block a user