clash-linux commited on
Commit
d9692e9
·
verified ·
1 Parent(s): 9fd3d43

Upload 18 files

Browse files
Files changed (2) hide show
  1. app/main.py +0 -46
  2. 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 config_yaml and isinstance(config_yaml, dict):
319
- # 确保proxies存在并且是一个有效的列表
320
- if "proxies" not in config_yaml or not isinstance(config_yaml["proxies"], list):
321
- logger.warning("配置中未找到有效的proxies列表,尝试保留原始内容")
 
 
 
 
 
 
 
 
 
 
 
322
 
323
- # 即使没有proxy-groups,也先保留所有已有的proxies
324
- if "proxies" in config_yaml and isinstance(config_yaml["proxies"], list):
325
- proxies_list = config_yaml["proxies"]
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
- logger.info(f"找到 {len(proxy_names)} 个代理节点")
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
- # 如果没有proxy-groups,添加基本的proxy-groups
406
- elif not "proxy-groups" in config_yaml:
407
- # 添加GLOBAL策略组
408
- logger.info("添加GLOBAL策略组")
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": global_proxies
422
  }]
423
- config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True)
 
424
  has_patch = True
 
 
 
 
 
425
 
426
- # 如果既没有proxies也没有proxy-groups,添加基本配置
427
- elif "proxies" not in config_yaml and "proxy-groups" not in config_yaml:
428
- # 可能不是Clash配置或非常基础的配置
429
- logger.warning("配置中未找到proxies和proxy-groups,添加基本配置")
430
- config_yaml["proxies"] = [{"name": "DIRECT", "type": "direct"}]
431
- config_yaml["proxy-groups"] = [{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
432
  "name": "GLOBAL",
433
  "type": "select",
434
- "proxies": ["DIRECT"]
435
- }]
436
- config_content = yaml.dump(config_yaml, sort_keys=False, allow_unicode=True)
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
- else:
452
- logger.info("检测到已有proxy-groups或GLOBAL配置,跳过添加")
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
- with open(self.config_path, "w", encoding="utf-8") as f:
488
- f.write(config_content)
489
- logger.info("已修补配置文件以添加必要的设置")
 
 
 
 
 
 
490
 
491
  except Exception as e:
492
- logger.error(f"修补配置文件时出错: {str(e)}")
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
  """