import re import yaml import aiohttp import asyncio import datetime import sys import traceback from aiohttp import web, ClientTimeout, TCPConnector from urllib.parse import parse_qs from cachetools import TTLCache cache = TTLCache(maxsize=1000, ttl=1800) # 30 minutes cache CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" async def fetch_url(url, session, max_retries=3): headers = {"User-Agent": CHROME_USER_AGENT} for attempt in range(max_retries): try: async with session.get(url, headers=headers, timeout=ClientTimeout(total=40)) as response: response.raise_for_status() content = await response.read() return content.decode('utf-8', errors='ignore') except aiohttp.ClientError as e: print(f"Attempt {attempt + 1} failed: {str(e)}", flush=True) if attempt == max_retries - 1: raise await asyncio.sleep(1) async def extract_and_transform_proxies(input_text): try: data = yaml.safe_load(input_text) if isinstance(data, dict) and 'proxies' in data: proxies_list = data['proxies'] elif isinstance(data, list): proxies_list = data else: proxies_match = re.search(r'proxies:\s*\n((?:[-\s]*{.*\n?)*)', input_text, re.MULTILINE) if proxies_match: proxies_text = proxies_match.group(1) proxies_list = yaml.safe_load(proxies_text) else: return "未找到有效的代理配置" except yaml.YAMLError: return "YAML解析错误" if not proxies_list: return "未找到有效的代理配置" transformed_proxies = [] for proxy in proxies_list: if proxy.get('type') in ['ss', 'trojan']: name = proxy.get('name', '').strip() server = proxy.get('server', '').strip() port = str(proxy.get('port', '')).strip() parts = [f"{name} = {proxy['type']}, {server}, {port}"] if proxy['type'] == 'ss': if 'cipher' in proxy: parts.append(f"encrypt-method={proxy['cipher'].strip()}") if 'password' in proxy: parts.append(f"password={proxy['password'].strip()}") elif proxy['type'] == 'trojan': if 'password' in proxy: parts.append(f"password={proxy['password'].strip()}") if 'sni' in proxy: parts.append(f"sni={proxy['sni'].strip()}") if 'skip-cert-verify' in proxy: parts.append(f"skip-cert-verify={str(proxy['skip-cert-verify']).lower()}") if 'udp' in proxy: parts.append(f"udp-relay={'true' if proxy['udp'] in [True, 'true', 'True'] else 'false'}") transformed_proxies.append(", ".join(parts)) return "\n".join(transformed_proxies) def get_client_ip(request): """获取客户端真实IP地址""" headers_to_check = [ 'X-Forwarded-For', 'X-Real-IP', 'CF-Connecting-IP', # Cloudflare 'True-Client-IP', # Akamai and Cloudflare 'X-Client-IP', ] for header in headers_to_check: ip = request.headers.get(header) if ip: # X-Forwarded-For可能包含多个IP,我们取第一个 return ip.split(',')[0].strip() # 如果没有找到,返回远程地址 return request.remote async def handle_request(request): if request.path == '/': query_params = parse_qs(request.query_string) if 'url' in query_params: url = query_params['url'][0] cache_hit = False if url in cache: result = cache[url] cache_hit = True else: try: async with aiohttp.ClientSession(connector=TCPConnector(ssl=False)) as session: input_text = await fetch_url(url, session) result = await extract_and_transform_proxies(input_text) cache[url] = result except Exception as e: print(f"Error processing request: {str(e)}", flush=True) traceback.print_exc() return web.Response(text=f"Error: {str(e)}", status=500) proxy_count = result.count('\n') + 1 if result and result != "未找到有效的代理配置" else 0 return web.Response(text=result, content_type='text/plain', headers={'X-Proxy-Count': str(proxy_count), 'X-Cache-Hit': str(cache_hit)}) else: usage_guide = """
使用方法:在URL参数中提供包含代理配置的网址。
示例:http://localhost:8080/?url=https://example.com/path-to-proxy-config