mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-05-22 08:47:11 +08:00
feat(proxy): 添加动态代理支持
- 在代理获取逻辑中集成动态代理 API 调用 - 新增动态代理配置界面和 API 接口 - 扩展设置模型以支持动态代理参数 - 更新前端设置页面和 JavaScript 逻辑
This commit is contained in:
@@ -178,6 +178,37 @@ SETTING_DEFINITIONS: Dict[str, SettingDefinition] = {
|
||||
description="代理密码",
|
||||
is_secret=True
|
||||
),
|
||||
"proxy_dynamic_enabled": SettingDefinition(
|
||||
db_key="proxy.dynamic_enabled",
|
||||
default_value=False,
|
||||
category=SettingCategory.PROXY,
|
||||
description="是否启用动态代理"
|
||||
),
|
||||
"proxy_dynamic_api_url": SettingDefinition(
|
||||
db_key="proxy.dynamic_api_url",
|
||||
default_value="",
|
||||
category=SettingCategory.PROXY,
|
||||
description="动态代理 API 地址,返回代理 URL 字符串"
|
||||
),
|
||||
"proxy_dynamic_api_key": SettingDefinition(
|
||||
db_key="proxy.dynamic_api_key",
|
||||
default_value="",
|
||||
category=SettingCategory.PROXY,
|
||||
description="动态代理 API 密钥(可选)",
|
||||
is_secret=True
|
||||
),
|
||||
"proxy_dynamic_api_key_header": SettingDefinition(
|
||||
db_key="proxy.dynamic_api_key_header",
|
||||
default_value="X-API-Key",
|
||||
category=SettingCategory.PROXY,
|
||||
description="动态代理 API 密钥请求头名称"
|
||||
),
|
||||
"proxy_dynamic_result_field": SettingDefinition(
|
||||
db_key="proxy.dynamic_result_field",
|
||||
default_value="",
|
||||
category=SettingCategory.PROXY,
|
||||
description="从 JSON 响应中提取代理 URL 的字段路径(留空则使用响应原文)"
|
||||
),
|
||||
|
||||
# 注册配置
|
||||
"registration_max_retries": SettingDefinition(
|
||||
@@ -335,6 +366,7 @@ SETTING_TYPES: Dict[str, Type] = {
|
||||
"log_retention_days": int,
|
||||
"proxy_enabled": bool,
|
||||
"proxy_port": int,
|
||||
"proxy_dynamic_enabled": bool,
|
||||
"registration_max_retries": int,
|
||||
"registration_timeout": int,
|
||||
"registration_default_password_length": int,
|
||||
@@ -534,6 +566,11 @@ class Settings(BaseModel):
|
||||
proxy_port: int = 7890
|
||||
proxy_username: Optional[str] = None
|
||||
proxy_password: Optional[SecretStr] = None
|
||||
proxy_dynamic_enabled: bool = False
|
||||
proxy_dynamic_api_url: str = ""
|
||||
proxy_dynamic_api_key: Optional[SecretStr] = None
|
||||
proxy_dynamic_api_key_header: str = "X-API-Key"
|
||||
proxy_dynamic_result_field: str = ""
|
||||
|
||||
@property
|
||||
def proxy_url(self) -> Optional[str]:
|
||||
|
||||
@@ -37,7 +37,8 @@ def get_proxy_for_registration(db) -> Tuple[Optional[str], Optional[int]]:
|
||||
|
||||
策略:
|
||||
1. 优先从代理列表中随机选择一个启用的代理
|
||||
2. 如果代理列表为空,使用系统设置中的默认代理
|
||||
2. 如果代理列表为空且启用了动态代理,调用动态代理 API 获取
|
||||
3. 否则使用系统设置中的静态默认代理
|
||||
|
||||
Returns:
|
||||
Tuple[proxy_url, proxy_id]: 代理 URL 和代理 ID(如果来自代理列表)
|
||||
@@ -47,10 +48,11 @@ def get_proxy_for_registration(db) -> Tuple[Optional[str], Optional[int]]:
|
||||
if proxy:
|
||||
return proxy.proxy_url, proxy.id
|
||||
|
||||
# 代理列表为空,使用系统设置中的默认代理
|
||||
settings = get_settings()
|
||||
if settings.proxy_enabled and settings.proxy_url:
|
||||
return settings.proxy_url, None
|
||||
# 代理列表为空,尝试动态代理或静态代理
|
||||
from ...core.dynamic_proxy import get_proxy_url_for_task
|
||||
proxy_url = get_proxy_url_for_task()
|
||||
if proxy_url:
|
||||
return proxy_url, None
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
@@ -79,6 +79,11 @@ async def get_all_settings():
|
||||
"port": settings.proxy_port,
|
||||
"username": settings.proxy_username,
|
||||
"has_password": bool(settings.proxy_password),
|
||||
"dynamic_enabled": settings.proxy_dynamic_enabled,
|
||||
"dynamic_api_url": settings.proxy_dynamic_api_url,
|
||||
"dynamic_api_key_header": settings.proxy_dynamic_api_key_header,
|
||||
"dynamic_result_field": settings.proxy_dynamic_result_field,
|
||||
"has_dynamic_api_key": bool(settings.proxy_dynamic_api_key and settings.proxy_dynamic_api_key.get_secret_value()),
|
||||
},
|
||||
"registration": {
|
||||
"max_retries": settings.registration_max_retries,
|
||||
@@ -199,6 +204,91 @@ async def test_proxy_settings(request: ProxySettings):
|
||||
}
|
||||
|
||||
|
||||
@router.get("/proxy/dynamic")
|
||||
async def get_dynamic_proxy_settings():
|
||||
"""获取动态代理设置"""
|
||||
settings = get_settings()
|
||||
return {
|
||||
"enabled": settings.proxy_dynamic_enabled,
|
||||
"api_url": settings.proxy_dynamic_api_url,
|
||||
"api_key_header": settings.proxy_dynamic_api_key_header,
|
||||
"result_field": settings.proxy_dynamic_result_field,
|
||||
"has_api_key": bool(settings.proxy_dynamic_api_key and settings.proxy_dynamic_api_key.get_secret_value()),
|
||||
}
|
||||
|
||||
|
||||
class DynamicProxySettings(BaseModel):
|
||||
"""动态代理设置"""
|
||||
enabled: bool = False
|
||||
api_url: str = ""
|
||||
api_key: Optional[str] = None
|
||||
api_key_header: str = "X-API-Key"
|
||||
result_field: str = ""
|
||||
|
||||
|
||||
@router.post("/proxy/dynamic")
|
||||
async def update_dynamic_proxy_settings(request: DynamicProxySettings):
|
||||
"""更新动态代理设置"""
|
||||
update_dict = {
|
||||
"proxy_dynamic_enabled": request.enabled,
|
||||
"proxy_dynamic_api_url": request.api_url,
|
||||
"proxy_dynamic_api_key_header": request.api_key_header,
|
||||
"proxy_dynamic_result_field": request.result_field,
|
||||
}
|
||||
if request.api_key is not None:
|
||||
update_dict["proxy_dynamic_api_key"] = request.api_key
|
||||
|
||||
update_settings(**update_dict)
|
||||
return {"success": True, "message": "动态代理设置已更新"}
|
||||
|
||||
|
||||
@router.post("/proxy/dynamic/test")
|
||||
async def test_dynamic_proxy(request: DynamicProxySettings):
|
||||
"""测试动态代理 API"""
|
||||
from ...core.dynamic_proxy import fetch_dynamic_proxy
|
||||
|
||||
if not request.api_url:
|
||||
raise HTTPException(status_code=400, detail="请填写动态代理 API 地址")
|
||||
|
||||
# 若未传入 api_key,使用已保存的
|
||||
api_key = request.api_key or ""
|
||||
if not api_key:
|
||||
settings = get_settings()
|
||||
if settings.proxy_dynamic_api_key:
|
||||
api_key = settings.proxy_dynamic_api_key.get_secret_value()
|
||||
|
||||
proxy_url = fetch_dynamic_proxy(
|
||||
api_url=request.api_url,
|
||||
api_key=api_key,
|
||||
api_key_header=request.api_key_header,
|
||||
result_field=request.result_field,
|
||||
)
|
||||
|
||||
if not proxy_url:
|
||||
return {"success": False, "message": "动态代理 API 返回为空或请求失败"}
|
||||
|
||||
# 用获取到的代理测试连通性
|
||||
import time
|
||||
from curl_cffi import requests as cffi_requests
|
||||
try:
|
||||
proxies = {"http": proxy_url, "https": proxy_url}
|
||||
start = time.time()
|
||||
resp = cffi_requests.get(
|
||||
"https://api.ipify.org?format=json",
|
||||
proxies=proxies,
|
||||
timeout=10,
|
||||
impersonate="chrome110"
|
||||
)
|
||||
elapsed = round((time.time() - start) * 1000)
|
||||
if resp.status_code == 200:
|
||||
ip = resp.json().get("ip", "")
|
||||
return {"success": True, "proxy_url": proxy_url, "ip": ip, "response_time": elapsed,
|
||||
"message": f"动态代理可用,出口 IP: {ip},响应时间: {elapsed}ms"}
|
||||
return {"success": False, "proxy_url": proxy_url, "message": f"代理连接失败: HTTP {resp.status_code}"}
|
||||
except Exception as e:
|
||||
return {"success": False, "proxy_url": proxy_url, "message": f"代理连接失败: {e}"}
|
||||
|
||||
|
||||
@router.get("/registration")
|
||||
async def get_registration_settings():
|
||||
"""获取注册设置"""
|
||||
|
||||
Reference in New Issue
Block a user