Selaa lähdekoodia

feat(zhch): 改进 Cloudflare Tunnel 设置,增加环境变量配置和下载逻辑

zhch158_admin 3 kuukautta sitten
vanhempi
commit
d8f5e3ced4
1 muutettua tiedostoa jossa 190 lisäystä ja 48 poistoa
  1. 190 48
      zhch/Cloudflare.py

+ 190 - 48
zhch/Cloudflare.py

@@ -1,74 +1,147 @@
 """
-使用 Cloudflare Tunnel 替代 ngrok
+使用 Cloudflare Tunnel 替代 ngrok - 改进版
 """
 import subprocess
 import time
-import json
-import requests
+import os
+import signal
+import sys
+import re
+from pathlib import Path
 
-def setup_cloudflare_tunnel(port=8101):
-    """设置 Cloudflare Tunnel"""
+def setup_environment():
+    """设置环境变量"""
+    proxy_url = "http://172.16.40.16:7280"
+    env = os.environ.copy()
+    env.update({
+        'HTTP_PROXY': proxy_url,
+        'HTTPS_PROXY': proxy_url,
+        'http_proxy': proxy_url,
+        'https_proxy': proxy_url,
+        # 设置 DNS
+        'GODEBUG': 'netdns=go+1',
+    })
+    return env
+
+def download_cloudflared():
+    """下载 cloudflared"""
+    print("🔄 Downloading cloudflared...")
     
-    print("🔄 Setting up Cloudflare Tunnel...")
+    # 确保目录存在
+    bin_dir = Path.home() / "zhch" / "bin"
+    bin_dir.mkdir(exist_ok=True)
     
-    # 1. 下载 cloudflared
-    download_cmd = [
-        'wget', '-O', '/tmp/cloudflared',
-        'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64'
-    ]
+    cloudflared_path = bin_dir / "cloudflared"
+    
+    # 如果已存在,跳过下载
+    if cloudflared_path.exists():
+        print("✅ Cloudflared already exists")
+        return str(cloudflared_path)
+    
+    # 下载命令
+    download_url = "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64"
+    download_cmd = ['curl', '-L', '-o', str(cloudflared_path), download_url]
     
     try:
-        subprocess.run(download_cmd, check=True, env={
-            'https_proxy': 'http://172.16.40.16:7280',
-            'http_proxy': 'http://172.16.40.16:7280'
-        })
-        subprocess.run(['chmod', '+x', '/tmp/cloudflared'], check=True)
-        print("✅ Cloudflared downloaded")
+        env = setup_environment()
+        result = subprocess.run(
+            download_cmd, 
+            check=True, 
+            env=env,
+            capture_output=True,
+            text=True,
+            timeout=300  # 5分钟超时
+        )
+        
+        # 设置执行权限
+        subprocess.run(['chmod', '+x', str(cloudflared_path)], check=True)
+        print("✅ Cloudflared downloaded successfully")
+        return str(cloudflared_path)
+        
+    except subprocess.TimeoutExpired:
+        print("❌ Download timeout - network may be slow")
+        return None
     except subprocess.CalledProcessError as e:
         print(f"❌ Download failed: {e}")
+        print(f"STDOUT: {e.stdout}")
+        print(f"STDERR: {e.stderr}")
+        return None
+
+def setup_cloudflare_tunnel(port=8101, timeout=60):
+    """设置 Cloudflare Tunnel"""
+    
+    print(f"🔄 Setting up Cloudflare Tunnel for port {port}...")
+    
+    # 下载 cloudflared
+    cloudflared_path = download_cloudflared()
+    if not cloudflared_path:
         return None
     
-    # 2. 启动临时隧道
+    # 准备命令
     tunnel_cmd = [
-        '/tmp/cloudflared', 'tunnel',
+        cloudflared_path, 'tunnel',
         '--url', f'http://localhost:{port}',
-        '--no-autoupdate'
+        '--no-autoupdate',
+        '--logfile', f'{Path.home()}/zhch/logs/cloudflared.log',
+        '--loglevel', 'info'
     ]
     
+    print(f"🚀 Starting tunnel: {' '.join(tunnel_cmd)}")
+    
     try:
-        print(f"🚀 Starting tunnel for port {port}...")
+        env = setup_environment()
         process = subprocess.Popen(
             tunnel_cmd,
             stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
+            stderr=subprocess.STDOUT,  # 合并输出
             text=True,
-            env={
-                'https_proxy': 'http://172.16.40.16:7280',
-                'http_proxy': 'http://172.16.40.16:7280'
-            }
+            env=env,
+            bufsize=1,  # 行缓冲
+            universal_newlines=True
         )
         
+        print("⏳ Waiting for tunnel to start...")
+        
         # 等待隧道启动并获取 URL
-        for _ in range(30):  # 等待最多30秒
+        start_time = time.time()
+        url_found = False
+        
+        while time.time() - start_time < timeout:
             if process.poll() is not None:
-                stdout, stderr = process.communicate()
-                print(f"❌ Process failed: {stderr}")
+                # 进程已终止
+                stdout, _ = process.communicate()
+                print(f"❌ Process terminated early:")
+                print(stdout)
                 return None
             
-            time.sleep(1)
-            
-            # 尝试从输出中提取 URL
             try:
-                # 读取一些输出
-                output = process.stdout.readline()
-                if 'trycloudflare.com' in output:
-                    url = output.split()[-1]
-                    print(f"✅ Tunnel URL: {url}")
-                    return url, process
-            except:
-                continue
+                # 非阻塞读取
+                line = process.stdout.readline()
+                if line:
+                    print(f"LOG: {line.strip()}")
+                    
+                    # 查找 trycloudflare.com URL
+                    if 'trycloudflare.com' in line:
+                        # 使用正则表达式提取 URL
+                        url_match = re.search(r'https://[a-zA-Z0-9-]+\.trycloudflare\.com', line)
+                        if url_match:
+                            url = url_match.group(0)
+                            print(f"✅ Tunnel URL found: {url}")
+                            return url, process
+                    
+                    # 检查错误信息
+                    if 'failed to request quick Tunnel' in line:
+                        print("❌ Failed to create tunnel - network connectivity issue")
+                        process.terminate()
+                        return None
+                
+            except Exception as e:
+                print(f"Error reading output: {e}")
+                break
+            
+            time.sleep(0.5)
         
-        print("⏰ Timeout waiting for tunnel URL")
+        print(f"⏰ Timeout after {timeout} seconds")
         process.terminate()
         return None
         
@@ -76,14 +149,83 @@ def setup_cloudflare_tunnel(port=8101):
         print(f"❌ Failed to start tunnel: {e}")
         return None
 
-if __name__ == "__main__":
-    result = setup_cloudflare_tunnel(8101)
+def test_local_service(port=8101):
+    """测试本地服务是否运行"""
+    import socket
+    try:
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        sock.settimeout(5)
+        result = sock.connect_ex(('localhost', port))
+        sock.close()
+        
+        if result == 0:
+            print(f"✅ Local service is running on port {port}")
+            return True
+        else:
+            print(f"❌ No service found on port {port}")
+            return False
+    except Exception as e:
+        print(f"❌ Error testing local service: {e}")
+        return False
+
+def main():
+    port = 8101
+    
+    print("🌐 Cloudflare Tunnel Setup")
+    print("=" * 50)
+    
+    # 检查本地服务
+    if not test_local_service(port):
+        print(f"⚠️ Warning: No service detected on port {port}")
+        response = input("Continue anyway? (y/N): ")
+        if response.lower() != 'y':
+            return
+    
+    # 设置隧道
+    result = setup_cloudflare_tunnel(port, timeout=120)
+    
     if result:
         url, process = result
+        print(f"\n🎉 Success!")
         print(f"🌐 Your service is now accessible at: {url}")
-        print("Press Ctrl+C to stop the tunnel")
-        try:
-            process.wait()
-        except KeyboardInterrupt:
+        print(f"🔗 Test URL: {url}/docs (if it's a FastAPI service)")
+        print("\nPress Ctrl+C to stop the tunnel")
+        
+        def signal_handler(sig, frame):
             print("\n🛑 Stopping tunnel...")
-            process.terminate()
+            process.terminate()
+            try:
+                process.wait(timeout=5)
+            except subprocess.TimeoutExpired:
+                process.kill()
+            print("✅ Tunnel stopped")
+            sys.exit(0)
+        
+        signal.signal(signal.SIGINT, signal_handler)
+        
+        try:
+            # 保持运行并显示日志
+            while process.poll() is None:
+                try:
+                    line = process.stdout.readline()
+                    if line:
+                        print(f"TUNNEL: {line.strip()}")
+                except KeyboardInterrupt:
+                    break
+                except Exception as e:
+                    print(f"Error: {e}")
+                    break
+        except Exception as e:
+            print(f"Error: {e}")
+        finally:
+            process.terminate()
+    else:
+        print("\n❌ Failed to setup tunnel")
+        print("\n🔧 Troubleshooting tips:")
+        print("1. Check if your proxy allows connections to api.trycloudflare.com")
+        print("2. Try using a different tunnel service (localtunnel, bore.pub)")
+        print("3. Contact your network administrator about tunnel access")
+        print("4. Use VS Code port forwarding if available")
+
+if __name__ == "__main__":
+    main()