mirror of
https://github.com/cnlimiter/codex-register.git
synced 2026-06-10 10:00:16 +08:00
feat(config): 采用列表模式
This commit is contained in:
@@ -484,14 +484,31 @@ def update_proxy_last_used(db: Session, proxy_id: int) -> bool:
|
||||
|
||||
|
||||
def get_random_proxy(db: Session) -> Optional[Proxy]:
|
||||
"""随机获取一个启用的代理"""
|
||||
"""随机获取一个启用的代理,优先返回 is_default=True 的代理"""
|
||||
import random
|
||||
# 优先返回默认代理
|
||||
default_proxy = db.query(Proxy).filter(Proxy.enabled == True, Proxy.is_default == True).first()
|
||||
if default_proxy:
|
||||
return default_proxy
|
||||
proxies = get_enabled_proxies(db)
|
||||
if not proxies:
|
||||
return None
|
||||
return random.choice(proxies)
|
||||
|
||||
|
||||
def set_proxy_default(db: Session, proxy_id: int) -> Optional[Proxy]:
|
||||
"""将指定代理设为默认,同时清除其他代理的默认标记"""
|
||||
# 清除所有默认标记
|
||||
db.query(Proxy).filter(Proxy.is_default == True).update({"is_default": False})
|
||||
# 设置新的默认代理
|
||||
proxy = db.query(Proxy).filter(Proxy.id == proxy_id).first()
|
||||
if proxy:
|
||||
proxy.is_default = True
|
||||
db.commit()
|
||||
db.refresh(proxy)
|
||||
return proxy
|
||||
|
||||
|
||||
def get_proxies_count(db: Session, enabled: Optional[bool] = None) -> int:
|
||||
"""获取代理数量"""
|
||||
query = db.query(func.count(Proxy.id))
|
||||
|
||||
@@ -156,6 +156,7 @@ class Proxy(Base):
|
||||
username = Column(String(100))
|
||||
password = Column(String(255))
|
||||
enabled = Column(Boolean, default=True)
|
||||
is_default = Column(Boolean, default=False) # 是否为默认代理
|
||||
priority = Column(Integer, default=0) # 优先级(保留字段)
|
||||
last_used = Column(DateTime) # 最后使用时间
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
@@ -171,6 +172,7 @@ class Proxy(Base):
|
||||
'port': self.port,
|
||||
'username': self.username,
|
||||
'enabled': self.enabled,
|
||||
'is_default': self.is_default or False,
|
||||
'priority': self.priority,
|
||||
'last_used': self.last_used.isoformat() if self.last_used else None,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
|
||||
@@ -110,6 +110,7 @@ class DatabaseSessionManager:
|
||||
("accounts", "subscription_type", "VARCHAR(20)"),
|
||||
("accounts", "subscription_at", "DATETIME"),
|
||||
("accounts", "cookies", "TEXT"),
|
||||
("proxies", "is_default", "BOOLEAN DEFAULT 0"),
|
||||
]
|
||||
|
||||
# 确保新表存在(create_tables 已处理,此处兜底)
|
||||
|
||||
@@ -347,18 +347,22 @@ def _run_sync_registration_task(task_uuid: str, email_service_type: str, proxy:
|
||||
saved_account = db.query(AccountModel).filter_by(email=result.email).first()
|
||||
if saved_account and saved_account.access_token:
|
||||
token_data = generate_token_json(saved_account)
|
||||
# 解析指定 CPA 服务
|
||||
# 解析指定 CPA 服务,未指定则取第一个启用的服务
|
||||
_cpa_api_url = None
|
||||
_cpa_api_token = None
|
||||
_svc = None
|
||||
if cpa_service_id:
|
||||
try:
|
||||
_svc = crud.get_cpa_service_by_id(db, cpa_service_id)
|
||||
if _svc:
|
||||
_cpa_api_url = _svc.api_url
|
||||
_cpa_api_token = _svc.api_token
|
||||
log_callback(f"[CPA] 使用服务: {_svc.name}")
|
||||
except Exception:
|
||||
pass
|
||||
if _svc is None:
|
||||
svcs = crud.get_cpa_services(db, enabled=True)
|
||||
_svc = svcs[0] if svcs else None
|
||||
if _svc:
|
||||
_cpa_api_url = _svc.api_url
|
||||
_cpa_api_token = _svc.api_token
|
||||
log_callback(f"[CPA] 使用服务: {_svc.name}")
|
||||
cpa_success, cpa_msg = upload_to_cpa(token_data, api_url=_cpa_api_url, api_token=_cpa_api_token)
|
||||
if cpa_success:
|
||||
saved_account.cpa_uploaded = True
|
||||
|
||||
@@ -111,101 +111,6 @@ async def get_all_settings():
|
||||
}
|
||||
|
||||
|
||||
@router.get("/proxy")
|
||||
async def get_proxy_settings():
|
||||
"""获取代理设置"""
|
||||
settings = get_settings()
|
||||
|
||||
return {
|
||||
"enabled": settings.proxy_enabled,
|
||||
"type": settings.proxy_type,
|
||||
"host": settings.proxy_host,
|
||||
"port": settings.proxy_port,
|
||||
"username": settings.proxy_username,
|
||||
"has_password": bool(settings.proxy_password),
|
||||
"proxy_url": settings.proxy_url,
|
||||
}
|
||||
|
||||
|
||||
@router.post("/proxy")
|
||||
async def update_proxy_settings(request: ProxySettings):
|
||||
"""更新代理设置"""
|
||||
update_dict = {
|
||||
"proxy_enabled": request.enabled,
|
||||
"proxy_type": request.type,
|
||||
"proxy_host": request.host,
|
||||
"proxy_port": request.port,
|
||||
"proxy_username": request.username,
|
||||
}
|
||||
|
||||
if request.password:
|
||||
update_dict["proxy_password"] = request.password
|
||||
|
||||
update_settings(**update_dict)
|
||||
|
||||
return {"success": True, "message": "代理设置已更新"}
|
||||
|
||||
|
||||
@router.post("/proxy/test")
|
||||
async def test_proxy_settings(request: ProxySettings):
|
||||
"""测试代理连接"""
|
||||
import time
|
||||
from curl_cffi import requests as cffi_requests
|
||||
|
||||
# 构建代理 URL
|
||||
if request.type == "http":
|
||||
scheme = "http"
|
||||
elif request.type == "socks5":
|
||||
scheme = "socks5"
|
||||
else:
|
||||
raise HTTPException(status_code=400, detail="不支持的代理类型")
|
||||
|
||||
auth = ""
|
||||
if request.username and request.password:
|
||||
auth = f"{request.username}:{request.password}@"
|
||||
|
||||
proxy_url = f"{scheme}://{auth}{request.host}:{request.port}"
|
||||
|
||||
# 测试连接
|
||||
test_url = "https://api.ipify.org?format=json"
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
proxies = {
|
||||
"http": proxy_url,
|
||||
"https": proxy_url
|
||||
}
|
||||
|
||||
response = cffi_requests.get(
|
||||
test_url,
|
||||
proxies=proxies,
|
||||
timeout=3,
|
||||
impersonate="chrome110"
|
||||
)
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
|
||||
if response.status_code == 200:
|
||||
ip_info = response.json()
|
||||
return {
|
||||
"success": True,
|
||||
"ip": ip_info.get("ip", ""),
|
||||
"response_time": round(elapsed_time * 1000), # 毫秒
|
||||
"message": f"代理连接成功,出口 IP: {ip_info.get('ip', 'unknown')}"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"代理返回错误状态码: {response.status_code}"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"代理连接失败: {str(e)}"
|
||||
}
|
||||
|
||||
|
||||
@router.get("/proxy/dynamic")
|
||||
async def get_dynamic_proxy_settings():
|
||||
"""获取动态代理设置"""
|
||||
@@ -639,6 +544,16 @@ async def delete_proxy_item(proxy_id: int):
|
||||
return {"success": True, "message": "代理已删除"}
|
||||
|
||||
|
||||
@router.post("/proxies/{proxy_id}/set-default")
|
||||
async def set_proxy_default(proxy_id: int):
|
||||
"""将指定代理设为默认"""
|
||||
with get_db() as db:
|
||||
proxy = crud.set_proxy_default(db, proxy_id)
|
||||
if not proxy:
|
||||
raise HTTPException(status_code=404, detail="代理不存在")
|
||||
return {"success": True, "proxy": proxy.to_dict()}
|
||||
|
||||
|
||||
@router.post("/proxies/{proxy_id}/test")
|
||||
async def test_proxy_item(proxy_id: int):
|
||||
"""测试单个代理"""
|
||||
@@ -774,77 +689,6 @@ async def disable_proxy(proxy_id: int):
|
||||
return {"success": True, "message": "代理已禁用"}
|
||||
|
||||
|
||||
# ============== CPA 设置 ==============
|
||||
|
||||
class CPASettings(BaseModel):
|
||||
"""CPA 设置"""
|
||||
enabled: bool = False
|
||||
api_url: str = ""
|
||||
api_token: str = ""
|
||||
|
||||
|
||||
class CPATestRequest(BaseModel):
|
||||
"""CPA 测试请求"""
|
||||
api_url: str
|
||||
api_token: str
|
||||
|
||||
|
||||
@router.get("/cpa")
|
||||
async def get_cpa_settings():
|
||||
"""获取 CPA 设置"""
|
||||
settings = get_settings()
|
||||
|
||||
return {
|
||||
"enabled": settings.cpa_enabled,
|
||||
"api_url": settings.cpa_api_url,
|
||||
"has_token": bool(settings.cpa_api_token and settings.cpa_api_token.get_secret_value()),
|
||||
}
|
||||
|
||||
|
||||
@router.post("/cpa")
|
||||
async def update_cpa_settings(request: CPASettings):
|
||||
"""更新 CPA 设置"""
|
||||
update_dict = {
|
||||
"cpa_enabled": request.enabled,
|
||||
"cpa_api_url": request.api_url,
|
||||
}
|
||||
|
||||
# 只有提供了 token 才更新
|
||||
if request.api_token:
|
||||
update_dict["cpa_api_token"] = request.api_token
|
||||
|
||||
update_settings(**update_dict)
|
||||
|
||||
return {"success": True, "message": "CPA 设置已更新"}
|
||||
|
||||
|
||||
@router.post("/cpa/test")
|
||||
async def test_cpa_connection(request: CPATestRequest):
|
||||
"""测试 CPA 连接"""
|
||||
from ...core.cpa_upload import test_cpa_connection as do_test
|
||||
|
||||
settings = get_settings()
|
||||
proxy = settings.proxy_url
|
||||
|
||||
# 如果传入 'use_saved_token',使用已保存的 token
|
||||
api_token = request.api_token
|
||||
if api_token == 'use_saved_token' or not api_token:
|
||||
if settings.cpa_api_token:
|
||||
api_token = settings.cpa_api_token.get_secret_value()
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "未配置 API Token"
|
||||
}
|
||||
|
||||
success, message = do_test(request.api_url, api_token, proxy)
|
||||
|
||||
return {
|
||||
"success": success,
|
||||
"message": message
|
||||
}
|
||||
|
||||
|
||||
# ============== Outlook 设置 ==============
|
||||
|
||||
class OutlookSettings(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user