mirror of
https://github.com/baoweise-bot/aimili-vpngate.git
synced 2026-09-09 01:36:52 +08:00
feat: optimize node fetching with conditional retries and implement post-connection proxy health checks and UI status updates
This commit is contained in:
+13
-1
@@ -359,9 +359,18 @@ def print_status():
|
|||||||
connecting_msg = state.get('last_check_message') or '正在建立加密隧道并验证路由规则...'
|
connecting_msg = state.get('last_check_message') or '正在建立加密隧道并验证路由规则...'
|
||||||
print_line(format_line("节点状态", f"{yellow}{connecting_msg}{reset}"))
|
print_line(format_line("节点状态", f"{yellow}{connecting_msg}{reset}"))
|
||||||
elif active_ip:
|
elif active_ip:
|
||||||
print_line(format_line("节点 IP", active_ip))
|
proxy_ip = state.get("proxy_ip", "-")
|
||||||
|
proxy_latency = state.get("proxy_latency_ms", 0)
|
||||||
|
proxy_ok = state.get("proxy_ok", False)
|
||||||
|
|
||||||
|
print_line(format_line("节点 IP (入口)", active_ip))
|
||||||
print_line(format_line("节点地区", active_loc))
|
print_line(format_line("节点地区", active_loc))
|
||||||
print_line(format_line("节点延迟 (直连测试)", latency))
|
print_line(format_line("节点延迟 (直连测试)", latency))
|
||||||
|
if proxy_ok and proxy_ip and proxy_ip != "-":
|
||||||
|
print_line(format_line("出口 IP (出站)", proxy_ip))
|
||||||
|
print_line(format_line("本地代理延迟", f"{proxy_latency} ms" if proxy_latency else "检测中..."))
|
||||||
|
else:
|
||||||
|
print_line(format_line("出口 IP (出站)", f"{red}[检测中/未就绪]{reset}"))
|
||||||
else:
|
else:
|
||||||
print_line(format_line("节点状态", "无活动连接"))
|
print_line(format_line("节点状态", "无活动连接"))
|
||||||
print_line()
|
print_line()
|
||||||
@@ -652,6 +661,9 @@ def get_status_state():
|
|||||||
state.get("active_openvpn_node_id", ""),
|
state.get("active_openvpn_node_id", ""),
|
||||||
state.get("last_check_message", ""),
|
state.get("last_check_message", ""),
|
||||||
state.get("active_node_latency", ""),
|
state.get("active_node_latency", ""),
|
||||||
|
state.get("proxy_ip", "-"),
|
||||||
|
state.get("proxy_latency_ms", 0),
|
||||||
|
state.get("proxy_ok", False),
|
||||||
check_port_listening(7928),
|
check_port_listening(7928),
|
||||||
check_service_active("aimilivpn.service"),
|
check_service_active("aimilivpn.service"),
|
||||||
check_openvpn_process(),
|
check_openvpn_process(),
|
||||||
|
|||||||
+31
-10
@@ -239,7 +239,7 @@ def fetch_api_text() -> str:
|
|||||||
"Accept": "text/plain,*/*",
|
"Accept": "text/plain,*/*",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
with urllib.request.urlopen(request, timeout=45) as response:
|
with urllib.request.urlopen(request, timeout=12) as response:
|
||||||
return response.read().decode("utf-8", errors="replace")
|
return response.read().decode("utf-8", errors="replace")
|
||||||
|
|
||||||
def parse_vpngate_rows(text: str) -> list[dict[str, str]]:
|
def parse_vpngate_rows(text: str) -> list[dict[str, str]]:
|
||||||
@@ -299,8 +299,12 @@ def fetch_candidates() -> list[dict[str, Any]]:
|
|||||||
candidates: list[dict[str, Any]] = []
|
candidates: list[dict[str, Any]] = []
|
||||||
seen_ips = set()
|
seen_ips = set()
|
||||||
|
|
||||||
log_to_json("INFO", "Main", "开始拉取官方 API 节点列表...")
|
# 检查本地是否有节点缓存,以确定最大重试尝试次数
|
||||||
for i in range(3):
|
has_cache = len(cached_nodes()) > 0
|
||||||
|
max_attempts = 1 if has_cache else 2
|
||||||
|
|
||||||
|
log_to_json("INFO", "Main", f"开始拉取官方 API 节点列表 (最大尝试次数: {max_attempts})...")
|
||||||
|
for i in range(max_attempts):
|
||||||
if i > 0:
|
if i > 0:
|
||||||
time.sleep(1.5)
|
time.sleep(1.5)
|
||||||
try:
|
try:
|
||||||
@@ -320,7 +324,7 @@ def fetch_candidates() -> list[dict[str, Any]]:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[fetch_candidates] Fetch {i+1} failed: {e}", flush=True)
|
print(f"[fetch_candidates] Fetch {i+1} failed: {e}", flush=True)
|
||||||
log_to_json("WARNING", "Main", f"第 {i+1} 次拉取 API 节点失败: {e}")
|
log_to_json("WARNING", "Main", f"第 {i+1} 次拉取 API 节点失败: {e}")
|
||||||
if i == 0 and not candidates:
|
if i == max_attempts - 1 and not candidates:
|
||||||
log_to_json("ERROR", "Main", f"获取官方 API 节点失败: {e}")
|
log_to_json("ERROR", "Main", f"获取官方 API 节点失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -819,6 +823,7 @@ def connect_node(node_id: str) -> str:
|
|||||||
print("[连接] 正在建立其他连接中,跳过此请求", flush=True)
|
print("[连接] 正在建立其他连接中,跳过此请求", flush=True)
|
||||||
return "Already connecting"
|
return "Already connecting"
|
||||||
is_connecting = True
|
is_connecting = True
|
||||||
|
active_openvpn_node_id = node_id
|
||||||
set_state(active_openvpn_node_id=node_id, is_connecting=True, active_node_latency="正在连接", last_check_message="正在初始化连接配置...")
|
set_state(active_openvpn_node_id=node_id, is_connecting=True, active_node_latency="正在连接", last_check_message="正在初始化连接配置...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -854,6 +859,8 @@ def connect_node(node_id: str) -> str:
|
|||||||
write_json(NODES_FILE, nodes)
|
write_json(NODES_FILE, nodes)
|
||||||
log_to_json("ERROR", "VPN", f"连接节点 {node_id} 失败: {message}")
|
log_to_json("ERROR", "VPN", f"连接节点 {node_id} 失败: {message}")
|
||||||
set_state(active_openvpn_node_id="", is_connecting=False, active_node_latency="无活动连接", last_check_message=f"连接失败: {message}")
|
set_state(active_openvpn_node_id="", is_connecting=False, active_node_latency="无活动连接", last_check_message=f"连接失败: {message}")
|
||||||
|
with lock:
|
||||||
|
active_openvpn_node_id = ""
|
||||||
raise RuntimeError(message)
|
raise RuntimeError(message)
|
||||||
|
|
||||||
active_openvpn_process = process
|
active_openvpn_process = process
|
||||||
@@ -882,6 +889,24 @@ def connect_node(node_id: str) -> str:
|
|||||||
if item["active"]:
|
if item["active"]:
|
||||||
item["probe_message"] = f"Active node. HTTP proxy: http://{LOCAL_PROXY_HOST}:{LOCAL_PROXY_PORT}"
|
item["probe_message"] = f"Active node. HTTP proxy: http://{LOCAL_PROXY_HOST}:{LOCAL_PROXY_PORT}"
|
||||||
write_json(NODES_FILE, nodes)
|
write_json(NODES_FILE, nodes)
|
||||||
|
|
||||||
|
set_state(last_check_message="正在测试本地代理出站联通性与出口 IP...")
|
||||||
|
res = check_proxy_health()
|
||||||
|
if res["ok"]:
|
||||||
|
set_state(
|
||||||
|
proxy_ok=True,
|
||||||
|
proxy_ip=res["ip"],
|
||||||
|
proxy_latency_ms=res["latency_ms"],
|
||||||
|
proxy_error=""
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
set_state(
|
||||||
|
proxy_ok=False,
|
||||||
|
proxy_ip="-",
|
||||||
|
proxy_latency_ms=0,
|
||||||
|
proxy_error=res.get("error", "未知错误")
|
||||||
|
)
|
||||||
|
|
||||||
latency_str = f"{last_active_latency} ms" if last_active_latency > 0 else "检测超时"
|
latency_str = f"{last_active_latency} ms" if last_active_latency > 0 else "检测超时"
|
||||||
set_state(active_openvpn_node_id=node_id, is_connecting=False, last_check_message=f"Connected {node_id}", active_node_latency=latency_str)
|
set_state(active_openvpn_node_id=node_id, is_connecting=False, last_check_message=f"Connected {node_id}", active_node_latency=latency_str)
|
||||||
log_to_json("INFO", "VPN", f"节点 {node_id} 连接成功,出口网卡 tun0 已启用")
|
log_to_json("INFO", "VPN", f"节点 {node_id} 连接成功,出口网卡 tun0 已启用")
|
||||||
@@ -915,12 +940,8 @@ def maintain_valid_nodes(force: bool = False) -> str:
|
|||||||
candidates = fetch_candidates()
|
candidates = fetch_candidates()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
vpn_utils.check_and_fix_dns()
|
vpn_utils.check_and_fix_dns()
|
||||||
try:
|
set_state(last_fetch_at=time.time(), last_fetch_status="error", last_fetch_message=str(exc))
|
||||||
set_state(is_connecting=True, last_check_message="解析失败重试:正在拉取最新的免费 VPN 节点列表...")
|
candidates = []
|
||||||
candidates = fetch_candidates()
|
|
||||||
except Exception as exc2:
|
|
||||||
set_state(last_fetch_at=time.time(), last_fetch_status="error", last_fetch_message=str(exc2))
|
|
||||||
candidates = []
|
|
||||||
|
|
||||||
if not candidates:
|
if not candidates:
|
||||||
is_connecting = False
|
is_connecting = False
|
||||||
|
|||||||
Reference in New Issue
Block a user