fix: run VLESS Reality on Xray instead of sing-box for v2rayN
sing-box Hy2 stays on 8443+; port 443 VLESS uses Xray which pairs reliably with v2rayN/Xray-core clients. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+27
-5
@@ -27,6 +27,7 @@ from stats import collect_node_stats
|
||||
ROOT = Path(os.environ.get("JIEDIAN_ROOT", Path(__file__).resolve().parents[1]))
|
||||
SECRET_FILE = ROOT / "data" / ".panel_secret"
|
||||
RENDER_SCRIPT = ROOT / "scripts" / "render-server.py"
|
||||
RENDER_XRAY_SCRIPT = ROOT / "scripts" / "render-xray.py"
|
||||
_apply_lock = threading.Lock()
|
||||
|
||||
|
||||
@@ -109,14 +110,28 @@ def render_singbox_config() -> tuple[bool, str]:
|
||||
env=env,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
return False, proc.stderr or proc.stdout or "配置生成失败"
|
||||
return False, proc.stderr or proc.stdout or "sing-box 配置生成失败"
|
||||
return True, "ok"
|
||||
|
||||
|
||||
def restart_singbox_async() -> None:
|
||||
"""后台重启 sing-box,避免添加/删除节点 API 长时间阻塞。"""
|
||||
def render_xray_config() -> tuple[bool, str]:
|
||||
env = os.environ.copy()
|
||||
env["JIEDIAN_ROOT"] = str(ROOT)
|
||||
proc = subprocess.run(
|
||||
["python3", str(RENDER_XRAY_SCRIPT)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
)
|
||||
if proc.returncode != 0:
|
||||
return False, proc.stderr or proc.stdout or "Xray 配置生成失败"
|
||||
return True, "ok"
|
||||
|
||||
|
||||
def restart_services_async() -> None:
|
||||
"""后台重启 sing-box 与 Xray。"""
|
||||
subprocess.Popen(
|
||||
["systemctl", "restart", "sing-box"],
|
||||
["systemctl", "restart", "xray", "sing-box"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
@@ -126,10 +141,17 @@ def apply_singbox() -> tuple[bool, str]:
|
||||
ok, msg = render_singbox_config()
|
||||
if not ok:
|
||||
return False, msg
|
||||
restart_singbox_async()
|
||||
ok, msg = render_xray_config()
|
||||
if not ok:
|
||||
return False, msg
|
||||
restart_services_async()
|
||||
return True, "ok"
|
||||
|
||||
|
||||
def restart_singbox_async() -> None:
|
||||
restart_services_async()
|
||||
|
||||
|
||||
def apply_singbox_background(on_fail=None) -> None:
|
||||
"""后台生成配置并重启 sing-box,避免阻塞 HTTP 请求导致 Nginx 503。"""
|
||||
|
||||
|
||||
@@ -19,10 +19,14 @@ ENV_FILE = ROOT / ".env"
|
||||
|
||||
CLASH_ADDR = "127.0.0.1:9090"
|
||||
_VLESS_INBOUND = "vless-reality-in"
|
||||
_XRAY_ACCESS_LOG = Path("/var/log/xray/access.log")
|
||||
_LOG_USER_RE = re.compile(
|
||||
r"\[([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\]\s+inbound connection"
|
||||
)
|
||||
_LOG_INDEX_RE = re.compile(r"\[(\d+)\] inbound connection")
|
||||
_LOG_XRAY_UUID_RE = re.compile(
|
||||
r"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})"
|
||||
)
|
||||
|
||||
_speed_cache: dict[int, tuple[float, int, int]] = {}
|
||||
_conn_cache: dict[str, dict[str, int | str]] = {}
|
||||
@@ -72,6 +76,26 @@ def fetch_clash_connections() -> tuple[list[dict], bool]:
|
||||
return payload.get("connections") or [], True
|
||||
|
||||
|
||||
def fetch_xray_access_uuids(nodes: list[dict]) -> set[str]:
|
||||
"""VLESS Reality 由 Xray 承载,从 access.log 读取近期活跃 UUID。"""
|
||||
if not _XRAY_ACCESS_LOG.exists():
|
||||
return set()
|
||||
try:
|
||||
text = _XRAY_ACCESS_LOG.read_text(encoding="utf-8", errors="ignore")
|
||||
except OSError:
|
||||
return set()
|
||||
known = {node["uuid"] for node in nodes}
|
||||
active: set[str] = set()
|
||||
for line in text.splitlines()[-400:]:
|
||||
if "accepted" not in line:
|
||||
continue
|
||||
for match in _LOG_XRAY_UUID_RE.finditer(line):
|
||||
uid = match.group(1)
|
||||
if uid in known:
|
||||
active.add(uid)
|
||||
return active
|
||||
|
||||
|
||||
def fetch_recent_log_uuids(nodes: list[dict]) -> set[str]:
|
||||
"""sing-box Clash API 不导出 user 字段,VLESS 多用户需从近期日志补全在线 UUID。"""
|
||||
try:
|
||||
@@ -343,6 +367,7 @@ def collect_node_stats() -> dict:
|
||||
uuid_to_node = {node["uuid"]: int(node["id"]) for node in nodes}
|
||||
connections, clash_ok = fetch_clash_connections()
|
||||
log_active = fetch_recent_log_uuids(nodes) if len(nodes) > 1 else set()
|
||||
log_active |= fetch_xray_access_uuids(nodes)
|
||||
active_by_uuid = _sync_connections(connections, nodes, uuid_to_node, log_active)
|
||||
single_node = len(nodes) == 1
|
||||
has_connections = len(connections) > 0
|
||||
|
||||
Reference in New Issue
Block a user