clash-linux commited on
Commit
395f8b0
·
verified ·
1 Parent(s): 3c9b458

Upload 17 files

Browse files
Files changed (3) hide show
  1. app/main.py +156 -3
  2. app/sub_manager.py +43 -4
  3. entrypoint.sh +8 -9
app/main.py CHANGED
@@ -225,6 +225,83 @@ def proxy_root():
225
  """处理根代理请求"""
226
  return proxy_request("")
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  @app.route('/', methods=['GET'])
229
  def index():
230
  """首页 - 提供简单说明"""
@@ -244,7 +321,77 @@ def index():
244
  .running {{ background-color: #dff0d8; color: #3c763d; }}
245
  .error {{ background-color: #f2dede; color: #a94442; }}
246
  .container {{ max-width: 800px; margin: 0 auto; }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  </head>
249
  <body>
250
  <div class='container'>
@@ -258,9 +405,15 @@ def index():
258
  <li>健康检查: /health</li>
259
  </ul>
260
  <h2>操作</h2>
261
- <p><a href='/api/refresh'>刷新订阅</a> (需要认证)</p>
262
- <p><a href='/api/nodes'>查看可用节点</a> (需要认证)</p>
263
- <p><a href='/api/current'>查看当前节点</a> (需要认证)</p>
 
 
 
 
 
 
264
  <h2>帮助</h2>
265
  <p>更多信息请查看 <a href='https://github.com/yourusername/simple-clash-relay'>文档</a>。</p>
266
  </div>
 
225
  """处理根代理请求"""
226
  return proxy_request("")
227
 
228
+ @app.route("/debug/clean", methods=["POST"])
229
+ @authenticate
230
+ def debug_clean():
231
+ """清理并重新初始化配置"""
232
+ global clash_manager, sub_manager, initialization_error
233
+
234
+ try:
235
+ # 停止Clash(如果正在运行)
236
+ if clash_manager is not None:
237
+ clash_manager.stop_clash()
238
+ clash_manager = None
239
+
240
+ # 删除配置文件
241
+ config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "config.yaml")
242
+ raw_config_path = f"{config_path}.raw"
243
+
244
+ files_to_delete = [config_path, raw_config_path]
245
+ deleted_files = []
246
+
247
+ for file_path in files_to_delete:
248
+ if os.path.exists(file_path):
249
+ try:
250
+ os.remove(file_path)
251
+ deleted_files.append(file_path)
252
+ except Exception as e:
253
+ logger.error(f"删除文件 {file_path} 失败: {str(e)}")
254
+
255
+ # 重新初始化
256
+ sub_manager = SubscriptionManager(
257
+ sub_url=SUB_URL,
258
+ config_path=config_path
259
+ )
260
+
261
+ # 加载订阅并转换为Clash配置
262
+ sub_manager.load_and_convert_sub()
263
+
264
+ # 初始化Clash管理器
265
+ clash_manager = ClashManager(
266
+ config_path=config_path,
267
+ clash_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "clash_core", "clash.meta-linux-amd64"),
268
+ api_port=CLASH_API_PORT,
269
+ proxy_port=CLASH_PROXY_PORT
270
+ )
271
+
272
+ # 启动Clash
273
+ clash_manager.start_clash()
274
+ initialization_error = None
275
+
276
+ return jsonify({
277
+ "success": True,
278
+ "message": f"配置已清理并重新初始化,删除的文件: {', '.join(deleted_files)}"
279
+ })
280
+
281
+ except Exception as e:
282
+ error_msg = f"清理配置失败: {str(e)}"
283
+ logger.error(error_msg)
284
+ initialization_error = error_msg
285
+ return jsonify({"success": False, "error": error_msg}), 500
286
+
287
+ @app.route("/debug/config", methods=["GET"])
288
+ @authenticate
289
+ def debug_show_config():
290
+ """显示当前配置文件内容"""
291
+ config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "config.yaml")
292
+
293
+ if not os.path.exists(config_path):
294
+ return jsonify({"success": False, "error": "配置文件不存在"}), 404
295
+
296
+ try:
297
+ with open(config_path, "r", encoding="utf-8") as f:
298
+ content = f.read()
299
+
300
+ return jsonify({"success": True, "content": content})
301
+
302
+ except Exception as e:
303
+ return jsonify({"success": False, "error": f"读取配置文件失败: {str(e)}"}), 500
304
+
305
  @app.route('/', methods=['GET'])
306
  def index():
307
  """首页 - 提供简单说明"""
 
321
  .running {{ background-color: #dff0d8; color: #3c763d; }}
322
  .error {{ background-color: #f2dede; color: #a94442; }}
323
  .container {{ max-width: 800px; margin: 0 auto; }}
324
+ .button {{
325
+ display: inline-block;
326
+ padding: 8px 16px;
327
+ background-color: #337ab7;
328
+ color: white;
329
+ text-decoration: none;
330
+ border-radius: 4px;
331
+ margin-right: 10px;
332
+ }}
333
+ .button.danger {{ background-color: #d9534f; }}
334
+ .debug-section {{
335
+ margin-top: 20px;
336
+ padding: 15px;
337
+ border: 1px dashed #ccc;
338
+ background-color: #f9f9f9;
339
+ }}
340
  </style>
341
+ <script>
342
+ function cleanConfig() {{
343
+ if (confirm('确定要清理配置并重启服务吗?')) {{
344
+ fetch('/debug/clean', {{
345
+ method: 'POST',
346
+ headers: {{ 'X-API-Key': prompt('请输入API密钥') }}
347
+ }})
348
+ .then(response => response.json())
349
+ .then(data => {{
350
+ alert(data.success ? data.message : '失败: ' + data.error);
351
+ location.reload();
352
+ }})
353
+ .catch(error => alert('请求失败: ' + error));
354
+ }}
355
+ }}
356
+
357
+ function viewConfig() {{
358
+ fetch('/debug/config', {{
359
+ headers: {{ 'X-API-Key': prompt('请输入API密钥') }}
360
+ }})
361
+ .then(response => response.json())
362
+ .then(data => {{
363
+ if (data.success) {{
364
+ const pre = document.createElement('pre');
365
+ pre.textContent = data.content;
366
+ pre.style.maxHeight = '500px';
367
+ pre.style.overflow = 'auto';
368
+ pre.style.backgroundColor = '#f5f5f5';
369
+ pre.style.padding = '10px';
370
+ pre.style.borderRadius = '4px';
371
+
372
+ const configDiv = document.getElementById('config-content');
373
+ configDiv.innerHTML = '';
374
+ configDiv.appendChild(pre);
375
+ }} else {{
376
+ alert('获取配置失败: ' + data.error);
377
+ }}
378
+ }})
379
+ .catch(error => alert('请求失败: ' + error));
380
+ }}
381
+
382
+ function refreshSubscription() {{
383
+ fetch('/api/refresh', {{
384
+ method: 'POST',
385
+ headers: {{ 'X-API-Key': prompt('请输入API密钥') }}
386
+ }})
387
+ .then(response => response.json())
388
+ .then(data => {{
389
+ alert(data.success ? data.message : '失败: ' + data.error);
390
+ location.reload();
391
+ }})
392
+ .catch(error => alert('请求失败: ' + error));
393
+ }}
394
+ </script>
395
  </head>
396
  <body>
397
  <div class='container'>
 
405
  <li>健康检查: /health</li>
406
  </ul>
407
  <h2>操作</h2>
408
+ <button class="button" onclick="refreshSubscription()">刷新订阅</button>
409
+
410
+ <div class="debug-section">
411
+ <h3>调试选项</h3>
412
+ <button class="button" onclick="viewConfig()">查看配置文件</button>
413
+ <button class="button danger" onclick="cleanConfig()">清理配置并重启</button>
414
+ <div id="config-content" style="margin-top: 15px;"></div>
415
+ </div>
416
+
417
  <h2>帮助</h2>
418
  <p>更多信息请查看 <a href='https://github.com/yourusername/simple-clash-relay'>文档</a>。</p>
419
  </div>
app/sub_manager.py CHANGED
@@ -128,6 +128,20 @@ class SubscriptionManager:
128
  except Exception as e:
129
  logger.error(f"创建数据目录失败: {str(e)}")
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  # 准备subconverter命令
132
  cmd = [
133
  self.subconverter_path,
@@ -177,6 +191,11 @@ class SubscriptionManager:
177
  try:
178
  with open(input_file, "r", encoding="utf-8") as f:
179
  content = f.read()
 
 
 
 
 
180
  with open(self.config_path, "w", encoding="utf-8") as f:
181
  f.write(content)
182
  logger.warning("尝试直接使用订阅内容作为配置文件")
@@ -213,6 +232,11 @@ class SubscriptionManager:
213
  try:
214
  with open(input_file, "r", encoding="utf-8") as f:
215
  content = f.read()
 
 
 
 
 
216
  with open(self.config_path, "w", encoding="utf-8") as f:
217
  f.write(content)
218
  logger.warning("使用订阅内容作为配置文件")
@@ -224,6 +248,20 @@ class SubscriptionManager:
224
  logger.error(f"执行subconverter时出错: {str(e)}")
225
  raise RuntimeError(f"配置转换失败: {str(e)}")
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  def _patch_config(self):
228
  """
229
  修改配置文件以确保端口设置正确,并兼容Clash Meta
@@ -244,23 +282,24 @@ class SubscriptionManager:
244
  # 这里需要检查配置是否为有效的YAML并进行适当修补
245
  # 为简单起见,我们只检查和添加一些基本端口配置
246
 
247
- if "port: 7890" not in config_content and "mixed-port: 7890" not in config_content:
248
  # 添加混合端口配置
249
  config_content = "mixed-port: 7890\n" + config_content
250
  has_patch = True
251
 
252
- if "external-controller: 127.0.0.1:9090" not in config_content and "external-controller: :9090" not in config_content:
 
253
  # 添加API控制器配置 (兼容Clash Meta)
254
  config_content = "external-controller: 127.0.0.1:9090\n" + config_content
255
  has_patch = True
256
 
257
  # Clash Meta特定配置
258
- if "find-process-mode: strict" not in config_content:
259
  config_content = "find-process-mode: strict\n" + config_content
260
  has_patch = True
261
 
262
  # 确保启用了API
263
- if "secret: " not in config_content:
264
  config_content = "secret: ''\n" + config_content
265
  has_patch = True
266
 
 
128
  except Exception as e:
129
  logger.error(f"创建数据目录失败: {str(e)}")
130
 
131
+ # 尝试直接读取订阅内容,确认它是否已经是Clash配置
132
+ try:
133
+ with open(input_file, "r", encoding="utf-8") as f:
134
+ content = f.read()
135
+
136
+ # 简单检查是否已经是Clash配置
137
+ if "proxies:" in content and ("port:" in content or "mixed-port:" in content):
138
+ logger.info("检测到输入文件已是Clash配置格式,直接使用")
139
+ with open(self.config_path, "w", encoding="utf-8") as f:
140
+ f.write(content)
141
+ return
142
+ except Exception as e:
143
+ logger.warning(f"读取输入文件时出错: {str(e)},将尝试转换")
144
+
145
  # 准备subconverter命令
146
  cmd = [
147
  self.subconverter_path,
 
191
  try:
192
  with open(input_file, "r", encoding="utf-8") as f:
193
  content = f.read()
194
+
195
+ # 确保它是有效的配置,如果是普通订阅格式,添加基本的Clash头
196
+ if "proxies:" not in content:
197
+ content = self._add_clash_headers() + content
198
+
199
  with open(self.config_path, "w", encoding="utf-8") as f:
200
  f.write(content)
201
  logger.warning("尝试直接使用订阅内容作为配置文件")
 
232
  try:
233
  with open(input_file, "r", encoding="utf-8") as f:
234
  content = f.read()
235
+
236
+ # 确保它是有效的配置,如果是普通订阅格式,添加基本的Clash头
237
+ if "proxies:" not in content:
238
+ content = self._add_clash_headers() + content
239
+
240
  with open(self.config_path, "w", encoding="utf-8") as f:
241
  f.write(content)
242
  logger.warning("使用订阅内容作为配置文件")
 
248
  logger.error(f"执行subconverter时出错: {str(e)}")
249
  raise RuntimeError(f"配置转换失败: {str(e)}")
250
 
251
+ def _add_clash_headers(self):
252
+ """添加基本的Clash配置头"""
253
+ return """# 自动生成的Clash配置
254
+ port: 7890
255
+ socks-port: 7891
256
+ mixed-port: 7890
257
+ allow-lan: true
258
+ mode: Rule
259
+ log-level: info
260
+ external-controller: 127.0.0.1:9090
261
+ secret: ""
262
+
263
+ """
264
+
265
  def _patch_config(self):
266
  """
267
  修改配置文件以确保端口设置正确,并兼容Clash Meta
 
282
  # 这里需要检查配置是否为有效的YAML并进行适当修补
283
  # 为简单起见,我们只检查和添加一些基本端口配置
284
 
285
+ if "mixed-port:" not in config_content and "port:" not in config_content:
286
  # 添加混合端口配置
287
  config_content = "mixed-port: 7890\n" + config_content
288
  has_patch = True
289
 
290
+ # 不要添加重复的external-controller配置
291
+ if "external-controller:" not in config_content:
292
  # 添加API控制器配置 (兼容Clash Meta)
293
  config_content = "external-controller: 127.0.0.1:9090\n" + config_content
294
  has_patch = True
295
 
296
  # Clash Meta特定配置
297
+ if "find-process-mode:" not in config_content:
298
  config_content = "find-process-mode: strict\n" + config_content
299
  has_patch = True
300
 
301
  # 确保启用了API
302
+ if "secret:" not in config_content:
303
  config_content = "secret: ''\n" + config_content
304
  has_patch = True
305
 
entrypoint.sh CHANGED
@@ -16,17 +16,16 @@ uname -a
16
  echo "${YELLOW}Running as user:${NC}"
17
  id
18
 
19
- echo "${YELLOW}Checking Clash Core:${NC}"
20
  file /app/clash_core/clash.meta-linux-amd64
21
  ls -la /app/clash_core/clash.meta-linux-amd64
22
- echo "${YELLOW}Checking Clash Core dependencies:${NC}"
23
- ldd /app/clash_core/clash.meta-linux-amd64 || echo "ldd command failed"
24
-
25
- echo "${YELLOW}Checking subconverter:${NC}"
26
- file /app/subconverter/subconverter
27
- ls -la /app/subconverter/subconverter
28
- echo "${YELLOW}Checking subconverter dependencies:${NC}"
29
- ldd /app/subconverter/subconverter || echo "ldd command failed"
30
 
31
  # 确保数据目录存在
32
  mkdir -p /app/data || echo "${YELLOW}Warning: Failed to create /app/data directory${NC}"
 
16
  echo "${YELLOW}Running as user:${NC}"
17
  id
18
 
19
+ echo "${YELLOW}Checking executables:${NC}"
20
  file /app/clash_core/clash.meta-linux-amd64
21
  ls -la /app/clash_core/clash.meta-linux-amd64
22
+
23
+ # 可选清理旧配置(如果指定CLEAN_CONFIG=true)
24
+ if [ "${CLEAN_CONFIG}" = "true" ]; then
25
+ echo "${YELLOW}Cleaning old config files...${NC}"
26
+ rm -f /app/data/config.yaml /app/data/config.yaml.raw
27
+ echo "${GREEN}Old config files cleaned${NC}"
28
+ fi
 
29
 
30
  # 确保数据目录存在
31
  mkdir -p /app/data || echo "${YELLOW}Warning: Failed to create /app/data directory${NC}"