Spaces:
Paused
Paused
Upload 18 files
Browse files- app/main.py +0 -46
- app/sub_manager.py +147 -149
app/main.py
CHANGED
|
@@ -244,23 +244,6 @@ def debug_show_config():
|
|
| 244 |
logger.error(f"读取配置文件时出错: {str(e)}")
|
| 245 |
return jsonify({"success": False, "error": str(e)}), 500
|
| 246 |
|
| 247 |
-
@app.route("/debug/raw-config", methods=["GET"])
|
| 248 |
-
@authenticate
|
| 249 |
-
def debug_show_raw_config():
|
| 250 |
-
"""获取并显示原始下载的订阅内容"""
|
| 251 |
-
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "config.yaml.raw")
|
| 252 |
-
|
| 253 |
-
if not os.path.exists(config_path):
|
| 254 |
-
return jsonify({"success": False, "error": "原始配置文件不存在"}), 404
|
| 255 |
-
|
| 256 |
-
try:
|
| 257 |
-
with open(config_path, "r", encoding="utf-8") as f:
|
| 258 |
-
content = f.read()
|
| 259 |
-
return jsonify({"success": True, "content": content})
|
| 260 |
-
except Exception as e:
|
| 261 |
-
logger.error(f"读取原始配置文件时出错: {str(e)}")
|
| 262 |
-
return jsonify({"success": False, "error": str(e)}), 500
|
| 263 |
-
|
| 264 |
# --- Yacd UI & Clash API 反向代理路由 ---
|
| 265 |
|
| 266 |
@app.route('/ui/')
|
|
@@ -439,34 +422,6 @@ def index():
|
|
| 439 |
configDiv.innerHTML = '<p style="color:red">请求失败: ' + error + '</p>';
|
| 440 |
}});
|
| 441 |
}}
|
| 442 |
-
|
| 443 |
-
function viewRawConfig() {{
|
| 444 |
-
const apiKey = prompt('请输入API密钥 (默认为 changeme)', 'changeme');
|
| 445 |
-
if (apiKey === null) return;
|
| 446 |
-
|
| 447 |
-
fetch('/debug/raw-config', {{
|
| 448 |
-
headers: {{ 'X-API-Key': apiKey }}
|
| 449 |
-
}})
|
| 450 |
-
.then(response => response.json())
|
| 451 |
-
.then(data => {{
|
| 452 |
-
const configDiv = document.getElementById('config-content');
|
| 453 |
-
configDiv.innerHTML = ''; // 清空之前的内容
|
| 454 |
-
if (data.success) {{
|
| 455 |
-
const pre = document.createElement('pre');
|
| 456 |
-
pre.textContent = data.content;
|
| 457 |
-
configDiv.appendChild(pre);
|
| 458 |
-
}} else {{
|
| 459 |
-
const errorP = document.createElement('p');
|
| 460 |
-
errorP.style.color = 'red';
|
| 461 |
-
errorP.textContent = '获取原始配置失败: ' + data.error;
|
| 462 |
-
configDiv.appendChild(errorP);
|
| 463 |
-
}}
|
| 464 |
-
}})
|
| 465 |
-
.catch(error => {{
|
| 466 |
-
const configDiv = document.getElementById('config-content');
|
| 467 |
-
configDiv.innerHTML = '<p style="color:red">请求失败: ' + error + '</p>';
|
| 468 |
-
}});
|
| 469 |
-
}}
|
| 470 |
</script>
|
| 471 |
</head>
|
| 472 |
<body>
|
|
@@ -484,7 +439,6 @@ def index():
|
|
| 484 |
<div class="debug-section">
|
| 485 |
<h3>调试选项</h3>
|
| 486 |
<button class="button" onclick="viewConfig()">查看当前配置文件</button>
|
| 487 |
-
<button class="button" onclick="viewRawConfig()">查看原始订阅内容</button>
|
| 488 |
<button class="button danger" onclick="if(confirm('确定要清理配置并重启服务吗?此操作不可逆!')) requestWithApiKey('/debug/clean')">清理配置并重启</button>
|
| 489 |
<div id="config-content" style="margin-top: 15px;"></div>
|
| 490 |
</div>
|
|
|
|
| 244 |
logger.error(f"读取配置文件时出错: {str(e)}")
|
| 245 |
return jsonify({"success": False, "error": str(e)}), 500
|
| 246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
# --- Yacd UI & Clash API 反向代理路由 ---
|
| 248 |
|
| 249 |
@app.route('/ui/')
|
|
|
|
| 422 |
configDiv.innerHTML = '<p style="color:red">请求失败: ' + error + '</p>';
|
| 423 |
}});
|
| 424 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 425 |
</script>
|
| 426 |
</head>
|
| 427 |
<body>
|
|
|
|
| 439 |
<div class="debug-section">
|
| 440 |
<h3>调试选项</h3>
|
| 441 |
<button class="button" onclick="viewConfig()">查看当前配置文件</button>
|
|
|
|
| 442 |
<button class="button danger" onclick="if(confirm('确定要清理配置并重启服务吗?此操作不可逆!')) requestWithApiKey('/debug/clean')">清理配置并重启</button>
|
| 443 |
<div id="config-content" style="margin-top: 15px;"></div>
|
| 444 |
</div>
|
app/sub_manager.py
CHANGED
|
@@ -303,10 +303,7 @@ secret: ""
|
|
| 303 |
config_content = "secret: ''\n" + config_content
|
| 304 |
has_patch = True
|
| 305 |
|
| 306 |
-
#
|
| 307 |
-
has_proxy_groups = "proxy-groups:" in config_content
|
| 308 |
-
has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
|
| 309 |
-
|
| 310 |
try:
|
| 311 |
import yaml
|
| 312 |
logger.info("正在使用PyYAML解析和修复配置")
|
|
@@ -314,182 +311,183 @@ secret: ""
|
|
| 314 |
# 解析配置
|
| 315 |
config_yaml = yaml.safe_load(config_content)
|
| 316 |
|
| 317 |
-
#
|
| 318 |
-
if
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
|
| 323 |
-
#
|
| 324 |
-
if
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
proxy_names = set()
|
|
|
|
| 329 |
for proxy in proxies_list:
|
| 330 |
if isinstance(proxy, dict) and "name" in proxy:
|
| 331 |
proxy_names.add(proxy["name"])
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
proxy_names.add("DIRECT")
|
| 336 |
-
proxy_names.add("REJECT")
|
| 337 |
-
|
| 338 |
-
# 检查并固定proxy-groups
|
| 339 |
-
if "proxy-groups" in config_yaml and isinstance(config_yaml["proxy-groups"], list):
|
| 340 |
-
groups_fixed = False
|
| 341 |
-
for group in config_yaml["proxy-groups"]:
|
| 342 |
-
if isinstance(group, dict) and "proxies" in group and "name" in group:
|
| 343 |
-
group_name = group["name"]
|
| 344 |
-
# 检查group["proxies"]中哪些是无效引用
|
| 345 |
-
invalid_proxies = []
|
| 346 |
-
valid_proxies = []
|
| 347 |
-
|
| 348 |
-
for proxy in group["proxies"]:
|
| 349 |
-
if proxy in proxy_names or proxy == group_name:
|
| 350 |
-
valid_proxies.append(proxy)
|
| 351 |
-
else:
|
| 352 |
-
logger.warning(f"删除代理组 {group_name} 中的无效引用: {proxy}")
|
| 353 |
-
invalid_proxies.append(proxy)
|
| 354 |
-
groups_fixed = True
|
| 355 |
-
|
| 356 |
-
# 确保代理组至少有一个有效代理
|
| 357 |
-
if not valid_proxies:
|
| 358 |
-
valid_proxies.append("DIRECT")
|
| 359 |
-
logger.warning(f"为空代理组 {group_name} 添加默认代理: DIRECT")
|
| 360 |
-
groups_fixed = True
|
| 361 |
-
|
| 362 |
-
group["proxies"] = valid_proxies
|
| 363 |
-
|
| 364 |
-
# 检查是否有GLOBAL组,如果没有,添加一个
|
| 365 |
-
has_global = False
|
| 366 |
-
for group in config_yaml["proxy-groups"]:
|
| 367 |
-
if isinstance(group, dict) and group.get("name") == "GLOBAL":
|
| 368 |
-
has_global = True
|
| 369 |
-
break
|
| 370 |
-
|
| 371 |
-
if not has_global:
|
| 372 |
-
# 添加GLOBAL策略组
|
| 373 |
-
logger.info("添加GLOBAL策略组")
|
| 374 |
-
|
| 375 |
-
# 确定要放入GLOBAL组的代理
|
| 376 |
-
global_proxies = ["DIRECT"]
|
| 377 |
-
# 从代理节点和其他策略组中选择要添加到GLOBAL的项
|
| 378 |
-
# 优先添加策略组
|
| 379 |
-
for group in config_yaml["proxy-groups"]:
|
| 380 |
-
if isinstance(group, dict) and "name" in group:
|
| 381 |
-
group_name = group["name"]
|
| 382 |
-
if group_name != "GLOBAL":
|
| 383 |
-
global_proxies.append(group_name)
|
| 384 |
-
|
| 385 |
-
# 如果没有其他策略组,添加所有代理节点
|
| 386 |
-
if len(global_proxies) <= 1: # 只有DIRECT
|
| 387 |
-
for proxy_name in proxy_names:
|
| 388 |
-
if proxy_name != "DIRECT" and proxy_name != "REJECT":
|
| 389 |
-
global_proxies.append(proxy_name)
|
| 390 |
-
|
| 391 |
-
# 添加GLOBAL组到配置
|
| 392 |
-
config_yaml["proxy-groups"].insert(0, {
|
| 393 |
-
"name": "GLOBAL",
|
| 394 |
-
"type": "select",
|
| 395 |
-
"proxies": global_proxies
|
| 396 |
-
})
|
| 397 |
-
groups_fixed = True
|
| 398 |
-
has_patch = True
|
| 399 |
-
|
| 400 |
-
# 如果修复了代理组,重新生成配置
|
| 401 |
-
if groups_fixed:
|
| 402 |
-
config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True)
|
| 403 |
-
has_patch = True
|
| 404 |
|
| 405 |
-
#
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
# 确定要放入GLOBAL组的代理
|
| 411 |
-
global_proxies = ["DIRECT"]
|
| 412 |
-
# 如果有代理节点,添加所有代理节点
|
| 413 |
-
for proxy_name in proxy_names:
|
| 414 |
-
if proxy_name != "DIRECT" and proxy_name != "REJECT":
|
| 415 |
-
global_proxies.append(proxy_name)
|
| 416 |
-
|
| 417 |
-
# 添加proxy-groups到配置
|
| 418 |
config_yaml["proxy-groups"] = [{
|
| 419 |
"name": "GLOBAL",
|
| 420 |
"type": "select",
|
| 421 |
-
"proxies":
|
| 422 |
}]
|
| 423 |
-
|
|
|
|
| 424 |
has_patch = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 425 |
|
| 426 |
-
#
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
logger.warning("
|
| 430 |
-
|
| 431 |
-
config_yaml["proxy-groups"] =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
"name": "GLOBAL",
|
| 433 |
"type": "select",
|
| 434 |
-
"proxies":
|
| 435 |
-
}
|
| 436 |
-
|
| 437 |
-
has_patch = True
|
| 438 |
-
else:
|
| 439 |
-
# 无法解析为有效的YAML,尝试简单文本修复
|
| 440 |
-
logger.warning("配置无法解析为有效的YAML,使用简单文本修复")
|
| 441 |
-
if not has_proxy_groups and not has_global_group:
|
| 442 |
-
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 443 |
-
config_content += """
|
| 444 |
-
proxy-groups:
|
| 445 |
-
- name: GLOBAL
|
| 446 |
-
type: select
|
| 447 |
-
proxies:
|
| 448 |
-
- DIRECT
|
| 449 |
-
"""
|
| 450 |
has_patch = True
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
except ImportError as e:
|
| 455 |
-
logger.error(f"导入PyYAML模块失败: {str(e)}")
|
| 456 |
-
#
|
|
|
|
|
|
|
| 457 |
if not has_proxy_groups and not has_global_group:
|
| 458 |
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 459 |
-
config_content += ""
|
| 460 |
-
proxy-groups:
|
| 461 |
-
- name: GLOBAL
|
| 462 |
-
type: select
|
| 463 |
-
proxies:
|
| 464 |
-
- DIRECT
|
| 465 |
-
"""
|
| 466 |
has_patch = True
|
| 467 |
else:
|
| 468 |
logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
|
| 469 |
except Exception as yaml_err:
|
| 470 |
-
logger.error(f"处理YAML配置时出错: {str(yaml_err)}")
|
| 471 |
-
#
|
|
|
|
|
|
|
| 472 |
if not has_proxy_groups and not has_global_group:
|
| 473 |
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 474 |
-
config_content += ""
|
| 475 |
-
proxy-groups:
|
| 476 |
-
- name: GLOBAL
|
| 477 |
-
type: select
|
| 478 |
-
proxies:
|
| 479 |
-
- DIRECT
|
| 480 |
-
"""
|
| 481 |
has_patch = True
|
| 482 |
else:
|
| 483 |
logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
|
| 484 |
|
| 485 |
-
#
|
| 486 |
if has_patch:
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 490 |
|
| 491 |
except Exception as e:
|
| 492 |
-
logger.error(f"
|
| 493 |
|
| 494 |
def _mask_url(self, url):
|
| 495 |
"""
|
|
|
|
| 303 |
config_content = "secret: ''\n" + config_content
|
| 304 |
has_patch = True
|
| 305 |
|
| 306 |
+
# 尝试解析YAML并修复代理组引用问题
|
|
|
|
|
|
|
|
|
|
| 307 |
try:
|
| 308 |
import yaml
|
| 309 |
logger.info("正在使用PyYAML解析和修复配置")
|
|
|
|
| 311 |
# 解析配置
|
| 312 |
config_yaml = yaml.safe_load(config_content)
|
| 313 |
|
| 314 |
+
# 检查解析结果是否为有效字典
|
| 315 |
+
if not isinstance(config_yaml, dict):
|
| 316 |
+
logger.error("配置文件解析结果不是有效的YAML字典,无法进行修复")
|
| 317 |
+
# 使用简单的文本分析,避免添加重复的配置
|
| 318 |
+
has_proxy_groups = "proxy-groups:" in config_content
|
| 319 |
+
has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
|
| 320 |
+
if not has_proxy_groups and not has_global_group:
|
| 321 |
+
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 322 |
+
config_content += "\nproxy-groups:\n - name: GLOBAL\n type: select\n proxies:\n - DIRECT\n"
|
| 323 |
+
has_patch = True
|
| 324 |
+
else:
|
| 325 |
+
logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
|
| 326 |
+
else:
|
| 327 |
+
# --- 开始修复逻辑 ---
|
| 328 |
+
groups_fixed = False
|
| 329 |
+
proxies_list = config_yaml.get("proxies")
|
| 330 |
|
| 331 |
+
# 1. 检查代理列表是否有效
|
| 332 |
+
if not proxies_list or not isinstance(proxies_list, list):
|
| 333 |
+
logger.error("配置文件缺少有效的 'proxies' 列表或列表为空!将仅使用 DIRECT 代理。请检查原始订阅内容。")
|
| 334 |
+
# 设置一个最小化的 proxies 和 proxy-groups
|
| 335 |
+
config_yaml["proxies"] = [{"name": "DIRECT", "type": "direct"}]
|
| 336 |
+
config_yaml["proxy-groups"] = [{
|
| 337 |
+
"name": "GLOBAL",
|
| 338 |
+
"type": "select",
|
| 339 |
+
"proxies": ["DIRECT"]
|
| 340 |
+
}]
|
| 341 |
+
proxy_names = {"DIRECT", "REJECT"}
|
| 342 |
+
groups_fixed = True # 标记需要重新生成配置内容
|
| 343 |
+
has_patch = True
|
| 344 |
+
else:
|
| 345 |
+
# 2. 代理列表有效,获取所有代理节点名称
|
| 346 |
proxy_names = set()
|
| 347 |
+
valid_proxies_list = []
|
| 348 |
for proxy in proxies_list:
|
| 349 |
if isinstance(proxy, dict) and "name" in proxy:
|
| 350 |
proxy_names.add(proxy["name"])
|
| 351 |
+
valid_proxies_list.append(proxy) # 只保留有效的代理定义
|
| 352 |
+
else:
|
| 353 |
+
logger.warning(f"配置文件中的 'proxies' 列表包含无效条目: {proxy}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
|
| 355 |
+
# 如果所有条目都无效,则回退
|
| 356 |
+
if not valid_proxies_list:
|
| 357 |
+
logger.error("配置文件中的 'proxies' 列表所有条目均无效!将仅使用 DIRECT 代理。")
|
| 358 |
+
config_yaml["proxies"] = [{"name": "DIRECT", "type": "direct"}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 359 |
config_yaml["proxy-groups"] = [{
|
| 360 |
"name": "GLOBAL",
|
| 361 |
"type": "select",
|
| 362 |
+
"proxies": ["DIRECT"]
|
| 363 |
}]
|
| 364 |
+
proxy_names = {"DIRECT", "REJECT"}
|
| 365 |
+
groups_fixed = True
|
| 366 |
has_patch = True
|
| 367 |
+
else:
|
| 368 |
+
config_yaml["proxies"] = valid_proxies_list # 更新为仅包含有效代理的列表
|
| 369 |
+
# 添加内置代理
|
| 370 |
+
proxy_names.add("DIRECT")
|
| 371 |
+
proxy_names.add("REJECT")
|
| 372 |
|
| 373 |
+
# 3. 修复或添加代理组
|
| 374 |
+
proxy_groups = config_yaml.get("proxy-groups", [])
|
| 375 |
+
if not isinstance(proxy_groups, list):
|
| 376 |
+
logger.warning("'proxy-groups' 不是一个列表,将重新创建")
|
| 377 |
+
proxy_groups = []
|
| 378 |
+
config_yaml["proxy-groups"] = proxy_groups
|
| 379 |
+
groups_fixed = True
|
| 380 |
+
|
| 381 |
+
has_global = False
|
| 382 |
+
valid_groups = []
|
| 383 |
+
for group in proxy_groups:
|
| 384 |
+
if not isinstance(group, dict) or "name" not in group or "type" not in group:
|
| 385 |
+
logger.warning(f"'proxy-groups' 中包含无效组定义: {group}")
|
| 386 |
+
groups_fixed = True
|
| 387 |
+
continue # 跳过无效组
|
| 388 |
+
|
| 389 |
+
if "proxies" in group:
|
| 390 |
+
if not isinstance(group["proxies"], list):
|
| 391 |
+
logger.warning(f"代理组 '{group['name']}' 的 'proxies' 不是列表,设置为 ['DIRECT']")
|
| 392 |
+
group["proxies"] = ["DIRECT"]
|
| 393 |
+
groups_fixed = True
|
| 394 |
+
else:
|
| 395 |
+
# 删除组中引用的不存在的代理
|
| 396 |
+
original_group_proxies = group["proxies"].copy()
|
| 397 |
+
group["proxies"] = [p for p in group["proxies"] if p in proxy_names or p == group["name"]]
|
| 398 |
+
if len(group["proxies"]) != len(original_group_proxies):
|
| 399 |
+
removed = set(original_group_proxies) - set(group["proxies"])
|
| 400 |
+
if removed:
|
| 401 |
+
logger.warning(f"删除代理组 '{group['name']}' 中的无效引用: {', '.join(removed)}")
|
| 402 |
+
groups_fixed = True
|
| 403 |
+
|
| 404 |
+
# 确保代理组至少有一个有效代理
|
| 405 |
+
if not group["proxies"]:
|
| 406 |
+
logger.warning(f"为空代理组 '{group['name']}' 添加默认代理: DIRECT")
|
| 407 |
+
group["proxies"].append("DIRECT")
|
| 408 |
+
groups_fixed = True
|
| 409 |
+
else:
|
| 410 |
+
# 如果组定义没有proxies列表(例如 url-test),通常是正常的
|
| 411 |
+
pass
|
| 412 |
+
|
| 413 |
+
valid_groups.append(group)
|
| 414 |
+
if group["name"] == "GLOBAL":
|
| 415 |
+
has_global = True
|
| 416 |
+
|
| 417 |
+
# 更新为只包含有效组定义的列表
|
| 418 |
+
config_yaml["proxy-groups"] = valid_groups
|
| 419 |
+
|
| 420 |
+
# 4. 如果没有 GLOBAL 组,添加一个
|
| 421 |
+
if not has_global:
|
| 422 |
+
logger.info("添加 GLOBAL 策略组")
|
| 423 |
+
# 确定要放入 GLOBAL 组的代理 (所有已知真实代理 + DIRECT)
|
| 424 |
+
global_proxies = [p for p in proxy_names if p not in ("DIRECT", "REJECT")]
|
| 425 |
+
global_proxies.sort() # 可选:排序
|
| 426 |
+
global_proxies.insert(0, "DIRECT") # 将 DIRECT 放前面
|
| 427 |
+
|
| 428 |
+
config_yaml["proxy-groups"].insert(0, {
|
| 429 |
"name": "GLOBAL",
|
| 430 |
"type": "select",
|
| 431 |
+
"proxies": global_proxies
|
| 432 |
+
})
|
| 433 |
+
groups_fixed = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
has_patch = True
|
| 435 |
+
|
| 436 |
+
# 5. 如果进行了修复,重新序列化 YAML
|
| 437 |
+
if groups_fixed:
|
| 438 |
+
try:
|
| 439 |
+
config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True, default_flow_style=None)
|
| 440 |
+
has_patch = True # 确保标记为已修改
|
| 441 |
+
except Exception as dump_err:
|
| 442 |
+
logger.error(f"重新序列化 YAML 失败: {dump_err}")
|
| 443 |
+
# 序列化失败,放弃修复,依赖原始 content + 基础 patch
|
| 444 |
+
# 重新读取原始content,只应用基础patch
|
| 445 |
+
with open(self.config_path, "r", encoding="utf-8") as f:
|
| 446 |
+
config_content = f.read()
|
| 447 |
+
if "mixed-port:" not in config_content and "port:" not in config_content: config_content = "mixed-port: 7890\n" + config_content
|
| 448 |
+
if "external-controller:" not in config_content: config_content = "external-controller: 127.0.0.1:9090\n" + config_content
|
| 449 |
+
if "find-process-mode:" not in config_content: config_content = "find-process-mode: strict\n" + config_content
|
| 450 |
+
if "secret:" not in config_content: config_content = "secret: ''\n" + config_content
|
| 451 |
+
has_patch = True # 标记基础 patch 已应用
|
| 452 |
+
|
| 453 |
+
# --- 处理 YAML 导入或解析错误的回退逻辑 ---
|
| 454 |
except ImportError as e:
|
| 455 |
+
logger.error(f"导入PyYAML模块失败: {str(e)}. 无法执行详细配置修复。")
|
| 456 |
+
# 使用简单的文本分析,避免添加重复的配置
|
| 457 |
+
has_proxy_groups = "proxy-groups:" in config_content
|
| 458 |
+
has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
|
| 459 |
if not has_proxy_groups and not has_global_group:
|
| 460 |
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 461 |
+
config_content += "\nproxy-groups:\n - name: GLOBAL\n type: select\n proxies:\n - DIRECT\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
has_patch = True
|
| 463 |
else:
|
| 464 |
logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
|
| 465 |
except Exception as yaml_err:
|
| 466 |
+
logger.error(f"处理YAML配置时出错: {str(yaml_err)}. 无法执行详细配置修复。")
|
| 467 |
+
# 使用简单的文本分析,避免添加重复的配置
|
| 468 |
+
has_proxy_groups = "proxy-groups:" in config_content
|
| 469 |
+
has_global_group = "GLOBAL" in config_content or "- name: GLOBAL" in config_content
|
| 470 |
if not has_proxy_groups and not has_global_group:
|
| 471 |
logger.info("未检测到proxy-groups或GLOBAL策略组,添加基本的GLOBAL策略组")
|
| 472 |
+
config_content += "\nproxy-groups:\n - name: GLOBAL\n type: select\n proxies:\n - DIRECT\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
has_patch = True
|
| 474 |
else:
|
| 475 |
logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
|
| 476 |
|
| 477 |
+
# --- 写回文件 ---
|
| 478 |
if has_patch:
|
| 479 |
+
logger.info("检测到配置更改,正在写回文件...")
|
| 480 |
+
try:
|
| 481 |
+
with open(self.config_path, "w", encoding="utf-8") as f:
|
| 482 |
+
f.write(config_content)
|
| 483 |
+
logger.info("已修补配置文件并成功保存")
|
| 484 |
+
except Exception as write_err:
|
| 485 |
+
logger.error(f"写回配置文件失败: {write_err}")
|
| 486 |
+
else:
|
| 487 |
+
logger.info("配置文件无需修补")
|
| 488 |
|
| 489 |
except Exception as e:
|
| 490 |
+
logger.error(f"修补配置文件过程中发生意外错误: {str(e)}")
|
| 491 |
|
| 492 |
def _mask_url(self, url):
|
| 493 |
"""
|