소스 검색

更新切换代理功能

jack 10 달 전
부모
커밋
3cfbac7624
2개의 변경된 파일172개의 추가작업 그리고 54개의 파일을 삭제
  1. 69 54
      manual/clash/switch_proxy.py
  2. 103 0
      test/my_proxy.py

+ 69 - 54
manual/clash/switch_proxy.py

@@ -4,72 +4,87 @@ import json
 import uuid
 import logging
 import websockets
-from typing import Optional
+from typing import Optional, List
 from websockets import WebSocketCommonProtocol
 
-# 配置日志
 logging.basicConfig(level=logging.INFO)
 
-# Clash API 的基础 URL
-CLASH_API_BASE_URL = "http://localhost:17888/api"
 
-# 服务的基础 URL 和端口
-SERVER_HOSTNAME = "proxy.wynd.network"
-SERVER_PORT = 4444
-SERVER_URL = f"wss://{SERVER_HOSTNAME}:{SERVER_PORT}/"
-TEST_USER_ID = '2pcRp86m1r76nSzdtGy1DNpXjrF'
-PROXY_URL = "http://127.0.0.1:17890"  # 代理地址
+class ClashProxyManager:
+    def __init__(self):
+        self.clash_api_base_url = [
+            "http://192.168.31.201:58001/api",
+            "http://192.168.31.201:58002/api",
+            "http://192.168.31.201:58003/api",
+            "http://192.168.31.201:58004/api",
+            "http://192.168.31.201:58005/api",
+            "http://192.168.31.201:58006/api",
+            "http://192.168.31.201:58007/api",
+            "http://192.168.31.201:58008/api",
+            "http://192.168.31.201:58009/api",
+            "http://192.168.31.201:58010/api",
+        ]
+        self.proxy_keyword = ['sg', 'SG', '新加坡', '马来西亚']
+        self.all_proxies = []
+        self.selected_proxies = []
 
+    def get_all_proxies(self, clash_tool_url: str) -> List[str]:
+        url = f"{clash_tool_url}/proxies"
+        try:
+            response = httpx.get(url)
+            response.raise_for_status()
+            proxies = response.json()
+            logging.info("Available proxies:")
+            # 输出读取的所有代理信息
+            # for proxy_name, proxy_info in proxies['proxies'].items():
+            #     logging.info(f"Name: {proxy_name}, Type: {proxy_info.get('type', 'Unknown')}")
+            return list(proxies['proxies'].keys())
+        except Exception as e:
+            logging.error(f"Failed to get proxies: {e}")
+            return []
 
-def get_all_proxies():
-    """获取Clash中所有可用的代理"""
-    url = f"{CLASH_API_BASE_URL}/proxies"
-    try:
-        response = httpx.get(url)
-        response.raise_for_status()  # 检查请求是否成功
-        proxies = response.json()
-        logging.info("Available proxies:")
-        for proxy_name, proxy_info in proxies['proxies'].items():
-            logging.info(f"Name: {proxy_name}, Type: {proxy_info.get('type', 'Unknown')}")
-        return list(proxies['proxies'].keys())
-    except Exception as e:
-        logging.error(f"Failed to get proxies: {e}")
-        return []
+    def filter_proxy(self):
+        for keyword in self.proxy_keyword:
+            for item in self.all_proxies:
+                if keyword.lower() in item.lower():
+                    self.selected_proxies.append(item)
 
+    def switch_proxy(self, proxy_name: str, clash_api_base_url: str) -> None:
+        url = f"{clash_api_base_url}/proxies/GLOBAL"
+        data = {"name": proxy_name}
+        try:
+            response = httpx.put(url, json=data)
+            if response.status_code == 204:
+                logging.info(f"Switched to proxy: {proxy_name}")
+            else:
+                logging.error(f"Failed to switch proxy: {response.status_code} - {proxy_name}")
+        except Exception as e:
+            logging.error(f"Failed to switch proxy: {e}")
 
-def switch_proxy(proxy_name):
-    """切换到指定的代理"""
-    url = f"{CLASH_API_BASE_URL}/proxies/GLOBAL"
-    data = {"name": proxy_name}
-    response = httpx.put(url, json=data)
-    if response.status_code == 204:
-        logging.info(f"Switched to proxy: {proxy_name}")
-    else:
-        logging.error(f"Failed to switch proxy: {response.status_code} - {proxy_name}")
+    def main(self) -> None:
+        # 读取所有代理
+        if not self.all_proxies:
+            for clash_tool_url in self.clash_api_base_url:
+                proxies = self.get_all_proxies(clash_tool_url)
+                if proxies:
+                    self.all_proxies = proxies
+                    break
 
+        if not self.all_proxies:
+            logging.error("Failed to get all proxies")
+            return
 
-def main():
-    # 获取所有代理
-    proxies = get_all_proxies()
-    if proxies:
-        logging.info(f"Found {len(proxies)} proxies.")
+        # 通过关键词过滤出需要的代理
+        self.filter_proxy()
+        if not self.selected_proxies:
+            logging.error("Failed to filter proxies")
+            return
 
-        ok_proxy_list = []
-
-        for proxy_name in proxies:
-            if proxy_name in ["DIRECT", "REJECT", "GLOBAL"]:
-                continue
-
-            # 切换到指定的代理
-            switch_proxy(proxy_name)
-            # 暂停一段时间,避免频繁切换
-            time.sleep(0.5)
-
-        for proxy_name in ok_proxy_list:
-            logging.info(f"Proxy {proxy_name} is OK.")
-    else:
-        logging.info("No proxies found. Exiting.")
+        # 遍历所有的线路api, 切换代理
+        for select_proxy, clash_api_base_url in zip(self.selected_proxies, self.clash_api_base_url):
+            self.switch_proxy(select_proxy, clash_api_base_url)
 
 
 if __name__ == "__main__":
-    main()
+    manager = ClashProxyManager()
+    manager.main()

+ 103 - 0
test/my_proxy.py

@@ -0,0 +1,103 @@
+import asyncio
+from aioquic.asyncio import connect
+from aioquic.quic.configuration import QuicConfiguration
+from aioquic.quic.events import StreamDataReceived, ConnectionTerminated
+from aioquic.asyncio.protocol import QuicConnectionProtocol
+import ssl
+
+# Trojan 配置
+config = {
+    "server": "lbso.bnnodeservice.com",  # 目标服务器地址
+    "port": 443,  # 目标服务器端口
+    "sni": "cert.bitbyte.one",  # SNI 伪装域名
+    "password": "f2e8e50c-ffb8-48a1-a460-2e72dfaf7845",  # 密码
+    "local_address": "127.0.0.1",  # 本地监听地址
+    "local_port": 1080,  # 本地监听端口
+}
+
+# 创建 QUIC 配置
+quic_config = QuicConfiguration(is_client=True, alpn_protocols=["h3"], max_datagram_frame_size=65536)
+quic_config.verify_mode = ssl.CERT_NONE  # 禁用证书验证
+quic_config.server_name = config["sni"]  # 设置 SNI
+
+
+# 创建 QUIC 连接
+class TrojanClientProtocol(QuicConnectionProtocol):
+    def __init__(self):
+        super().__init__()
+        self.writer = None
+
+    def connection_established(self, quic):
+        self.quic = quic
+
+    def quic_event_received(self, event):
+        if isinstance(event, StreamDataReceived):
+            if self.writer:
+                self.writer.write(event.data)
+                self.writer.drain()
+        elif isinstance(event, ConnectionTerminated):
+            if self.writer:
+                self.writer.close()
+
+
+# 处理客户端请求
+async def handle_client(reader, writer):
+    protocol = TrojanClientProtocol()
+    protocol.writer = writer
+
+    # 创建到目标服务器的 QUIC 连接
+    async with connect(
+            config["server"],
+            config["port"],
+            configuration=quic_config,
+            create_protocol=lambda: protocol,
+    ) as quic_connection:
+        # 发送密码
+        quic_connection.send_stream_data(0, config["password"].encode() + b"\r\n")
+
+        # 处理客户端请求
+        async def client_to_server():
+            try:
+                while True:
+                    data = await reader.read(4096)
+                    if not data:
+                        break
+                    quic_connection.send_stream_data(0, data)
+            except Exception as e:
+                print(f"Client to server error: {e}")
+            finally:
+                quic_connection.close()
+
+        # 处理服务器响应
+        async def server_to_client():
+            try:
+                while True:
+                    event = quic_connection.next_event()
+                    if isinstance(event, StreamDataReceived):
+                        writer.write(event.data)
+                        await writer.drain()
+                    elif isinstance(event, ConnectionTerminated):
+                        break
+            except Exception as e:
+                print(f"Server to client error: {e}")
+            finally:
+                writer.close()
+
+        # 启动两个任务
+        await asyncio.gather(client_to_server(), server_to_client())
+
+    # 关闭连接
+    writer.close()
+
+
+# 启动本地代理服务器
+async def start_proxy():
+    server = await asyncio.start_server(handle_client, config["local_address"], config["local_port"])
+    print(f"代理服务器已启动,监听地址:{config['local_address']}:{config['local_port']}")
+    async with server:
+        await server.serve_forever()
+
+
+# 运行代理服务器
+if __name__ == "__main__":
+    asyncio.run(start_proxy())