|
@@ -0,0 +1,91 @@
|
|
|
|
|
+"""
|
|
|
|
|
+使用 localtunnel 替代 ngrok
|
|
|
|
|
+"""
|
|
|
|
|
+import subprocess
|
|
|
|
|
+import time
|
|
|
|
|
+import re
|
|
|
|
|
+
|
|
|
|
|
+def setup_localtunnel(port=8101, subdomain=None):
|
|
|
|
|
+ """设置 localtunnel"""
|
|
|
|
|
+
|
|
|
|
|
+ print("🔄 Setting up localtunnel...")
|
|
|
|
|
+
|
|
|
|
|
+ # 1. 安装 localtunnel (需要 Node.js)
|
|
|
|
|
+ try:
|
|
|
|
|
+ # 检查 npm 是否可用
|
|
|
|
|
+ subprocess.run(['npm', '--version'], check=True, capture_output=True)
|
|
|
|
|
+ print("✅ npm is available")
|
|
|
|
|
+ except subprocess.CalledProcessError:
|
|
|
|
|
+ print("❌ npm not found. Please install Node.js first:")
|
|
|
|
|
+ print(" curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -")
|
|
|
|
|
+ print(" sudo apt-get install -y nodejs")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 安装 localtunnel
|
|
|
|
|
+ try:
|
|
|
|
|
+ env = {
|
|
|
|
|
+ 'https_proxy': 'http://172.16.40.16:7280',
|
|
|
|
|
+ 'http_proxy': 'http://172.16.40.16:7280'
|
|
|
|
|
+ }
|
|
|
|
|
+ subprocess.run(['npm', 'install', '-g', 'localtunnel'], check=True, env=env)
|
|
|
|
|
+ print("✅ localtunnel installed")
|
|
|
|
|
+ except subprocess.CalledProcessError as e:
|
|
|
|
|
+ print(f"❌ Installation failed: {e}")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ # 3. 启动隧道
|
|
|
|
|
+ cmd = ['lt', '--port', str(port)]
|
|
|
|
|
+ if subdomain:
|
|
|
|
|
+ cmd.extend(['--subdomain', subdomain])
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ print(f"🚀 Starting tunnel for port {port}...")
|
|
|
|
|
+ process = subprocess.Popen(
|
|
|
|
|
+ cmd,
|
|
|
|
|
+ stdout=subprocess.PIPE,
|
|
|
|
|
+ stderr=subprocess.PIPE,
|
|
|
|
|
+ text=True,
|
|
|
|
|
+ env={
|
|
|
|
|
+ 'https_proxy': 'http://172.16.40.16:7280',
|
|
|
|
|
+ 'http_proxy': 'http://172.16.40.16:7280'
|
|
|
|
|
+ }
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ # 等待并获取 URL
|
|
|
|
|
+ for _ in range(20):
|
|
|
|
|
+ output = process.stdout.readline()
|
|
|
|
|
+ if output:
|
|
|
|
|
+ print(f"Output: {output.strip()}")
|
|
|
|
|
+ # 查找 URL
|
|
|
|
|
+ url_match = re.search(r'https://.*?\.loca\.lt', output)
|
|
|
|
|
+ if url_match:
|
|
|
|
|
+ url = url_match.group(0)
|
|
|
|
|
+ print(f"✅ Tunnel URL: {url}")
|
|
|
|
|
+ return url, process
|
|
|
|
|
+
|
|
|
|
|
+ if process.poll() is not None:
|
|
|
|
|
+ stderr = process.stderr.read()
|
|
|
|
|
+ print(f"❌ Process failed: {stderr}")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ time.sleep(1)
|
|
|
|
|
+
|
|
|
|
|
+ print("⏰ Timeout waiting for tunnel URL")
|
|
|
|
|
+ process.terminate()
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"❌ Failed to start tunnel: {e}")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ result = setup_localtunnel(8101)
|
|
|
|
|
+ if result:
|
|
|
|
|
+ url, process = result
|
|
|
|
|
+ print(f"🌐 Your service is now accessible at: {url}")
|
|
|
|
|
+ print("Press Ctrl+C to stop the tunnel")
|
|
|
|
|
+ try:
|
|
|
|
|
+ process.wait()
|
|
|
|
|
+ except KeyboardInterrupt:
|
|
|
|
|
+ print("\n🛑 Stopping tunnel...")
|
|
|
|
|
+ process.terminate()
|