fix: multi-node online stats, per-node Hy2 ports, and panel reload stability

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-16 11:35:15 +08:00
parent 33533d7ebc
commit abbaac9520
11 changed files with 246 additions and 73 deletions
+23 -8
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import os
import secrets
import subprocess
import threading
from functools import wraps
from pathlib import Path
@@ -26,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"
_apply_lock = threading.Lock()
def _secret_key() -> str:
@@ -128,6 +130,18 @@ def apply_singbox() -> tuple[bool, str]:
return True, "ok"
def apply_singbox_background(on_fail=None) -> None:
"""后台生成配置并重启 sing-box,避免阻塞 HTTP 请求导致 Nginx 503。"""
def worker() -> None:
with _apply_lock:
ok, msg = apply_singbox()
if not ok and on_fail:
on_fail(msg)
threading.Thread(target=worker, daemon=True).start()
@app.route("/login", methods=["GET", "POST"])
def login():
if session.get("user"):
@@ -196,16 +210,19 @@ def api_add_node():
body = request.get_json(silent=True) or {}
name = (body.get("name") or request.form.get("name") or "新节点").strip()
node = add_node(name)
ok, msg = apply_singbox()
if not ok:
delete_node(node["id"])
return jsonify({"error": msg}), 500
env = load_env()
node_id = int(node["id"])
def on_fail(_msg: str) -> None:
delete_node(node_id)
apply_singbox_background(on_fail=on_fail)
return jsonify(
{
"id": node["id"],
"name": node["name"],
"links": build_links(node, env),
"pending": True,
}
)
@@ -217,11 +234,9 @@ def api_delete_node(node_id: int):
return jsonify({"error": "至少保留一个节点"}), 400
if not delete_node(node_id):
return jsonify({"error": "节点不存在"}), 404
ok, msg = apply_singbox()
if not ok:
return jsonify({"error": msg}), 500
apply_singbox_background()
return jsonify({"ok": True})
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5080)
app.run(host="127.0.0.1", port=5080, threaded=True)