diff --git a/vpn_utils.py b/vpn_utils.py index 57f8085..651e791 100644 --- a/vpn_utils.py +++ b/vpn_utils.py @@ -556,6 +556,9 @@ def diagnose_openvpn_failure(log_tail: list[str]) -> tuple[int, str]: if "connection refused" in joined_log: return 2004, "[ERR_OVPN_NODE_UNREACHABLE] 节点连接被拒绝。原因: 目的服务器未在指定端口监听,或者主动拒绝了连接。" + if "permission denied" in joined_log or "root privileges" in joined_log or "need root" in joined_log: + return 2002, "[ERR_OVPN_PERMISSION_DENIED] 权限不足。原因: 运行 OpenVPN 需要 root 权限,请确保以 root 用户身份或使用 sudo 运行本系统。" + if "options error" in joined_log: return 2007, "[ERR_OVPN_ROUTE_NOPULL] 获取/解析 PUSH 配置参数冲突。原因: 某些推送选项在当前版本的客户端或配置环境中不可用。" diff --git a/vpngate_manager.py b/vpngate_manager.py index 4d66556..7dab84a 100644 --- a/vpngate_manager.py +++ b/vpngate_manager.py @@ -739,11 +739,20 @@ def run_openvpn_until_ready(config_file: str, keep_alive: bool, route_nopull: bo def reader() -> None: assert process.stdout is not None for line in process.stdout: + line_str = line.rstrip() + level = "INFO" + line_lower = line_str.lower() + if "error" in line_lower or "failed" in line_lower or "cannot" in line_lower or "fatal" in line_lower or "permission denied" in line_lower: + level = "ERROR" + elif "warning" in line_lower or "warn" in line_lower or "deprecated" in line_lower: + level = "WARNING" + log_to_json(level, "VPN", f"[OpenVPN] {line_str}") + if not startup_done[0]: - lines.put(line.rstrip()) + lines.put(line_str) else: if keep_alive: - print(f"[OpenVPN] {line.rstrip()}", flush=True) + print(f"[OpenVPN] {line_str}", flush=True) if not startup_done[0]: lines.put(None) @@ -763,7 +772,7 @@ def run_openvpn_until_ready(config_file: str, keep_alive: bool, route_nopull: bo break if line: tail.append(line) - tail = tail[-8:] + tail = tail[-50:] if keep_alive: print(f"[OpenVPN] {line}", flush=True) lower = line.lower() @@ -2626,6 +2635,11 @@ INDEX_HTML = r"""
+ @@ -3069,6 +3083,7 @@ function getFilteredNodes() { const q = $("search").value.toLowerCase(); const selectedCountry = $("country_filter").value; const selectedIpType = $("ip_type_filter").value; + const selectedStatus = $("status_filter").value; return nodes.filter(n => { if (!n) return false; if (selectedCountry && n.country !== selectedCountry) { @@ -3082,6 +3097,12 @@ function getFilteredNodes() { return false; } } + if (selectedStatus === "available" && n.probe_status === "unavailable" && !n.active) { + return false; + } + if (selectedStatus === "unavailable" && (n.probe_status !== "unavailable" || n.active)) { + return false; + } const searchStr = [ n.country || "", n.country_short || "", n.ip || "", n.remote_host || "", n.proto || "", translateQuality(n.quality), translateIpType(n.ip_type), n.location || "", n.owner || "", n.as_name || "" @@ -3498,6 +3519,7 @@ async function load(){ $("search").oninput=()=>{ currentPage = 1; render(); }; $("country_filter").onchange=()=>{ currentPage = 1; render(); }; $("ip_type_filter").onchange=()=>{ currentPage = 1; render(); }; +$("status_filter").onchange=()=>{ currentPage = 1; render(); }; $("refresh").onclick=async()=>{ $("refresh").disabled=true;