File size: 2,596 Bytes
8551878
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# protobuf2openai/proxy_manager.py
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  # type: ignore

        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:
            # 已经是完整URL时直接返回(支持 http/https/socks)
            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}"

            # host:port 形式,默认按 socks5 处理
            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