|
|
|
|
|
import asyncio |
|
|
import logging |
|
|
import os |
|
|
from datetime import datetime |
|
|
from typing import Optional |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
def _resolve_default_proxy() -> Optional[str]: |
|
|
"""从环境变量或全局配置解析默认代理地址。""" |
|
|
env_proxy = os.getenv("WARP_PROXY_URL") or os.getenv("HTTP_PROXY") or os.getenv("http_proxy") |
|
|
if env_proxy: |
|
|
env_proxy = env_proxy.strip() |
|
|
if env_proxy: |
|
|
return env_proxy |
|
|
|
|
|
try: |
|
|
import config |
|
|
|
|
|
proxy = getattr(config, "PROXY_URL", None) |
|
|
if proxy: |
|
|
proxy = str(proxy).strip() |
|
|
if proxy: |
|
|
return proxy |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
class AsyncProxyManager: |
|
|
"""异步代理管理器""" |
|
|
|
|
|
def __init__(self): |
|
|
self.used_identifiers = {} |
|
|
self.lock = asyncio.Lock() |
|
|
self._default_proxy = _resolve_default_proxy() |
|
|
|
|
|
async def cleanup_expired_identifiers(self): |
|
|
"""清理过期的IP标识""" |
|
|
current_time = datetime.now() |
|
|
async with self.lock: |
|
|
expired_keys = [k for k, v in self.used_identifiers.items() if v < current_time] |
|
|
for key in expired_keys: |
|
|
del self.used_identifiers[key] |
|
|
|
|
|
async def get_proxy(self) -> Optional[str]: |
|
|
"""获取代理IP,若未配置则返回None表示直连。""" |
|
|
return self._default_proxy |
|
|
|
|
|
def format_proxy_for_httpx(self, proxy_str: str) -> Optional[str]: |
|
|
"""格式化代理为httpx可用的格式。""" |
|
|
if not proxy_str: |
|
|
return None |
|
|
|
|
|
proxy_str = proxy_str.strip() |
|
|
if not proxy_str: |
|
|
return None |
|
|
|
|
|
try: |
|
|
|
|
|
if proxy_str.startswith(("http://", "https://", "socks5://", "socks4://")): |
|
|
return proxy_str |
|
|
|
|
|
if '@' in proxy_str: |
|
|
credentials, host_port = proxy_str.split('@') |
|
|
user, password = credentials.split(':') |
|
|
host, port = host_port.split(':') |
|
|
return f"socks5://{user}:{password}@{host}:{port}" |
|
|
|
|
|
|
|
|
if ':' in proxy_str: |
|
|
host, port = proxy_str.split(':', 1) |
|
|
return f"socks5://{host}:{port}" |
|
|
|
|
|
logger.error(f"代理格式无法识别: {proxy_str}") |
|
|
return None |
|
|
except Exception as e: |
|
|
logger.error(f"格式化代理失败: {e}") |
|
|
return None |
|
|
|