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:
+23
-8
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user