Add default remote proxy support for Sub2API services.
Let Sub2API service settings store and load a default remote proxy so uploads can reuse the target service's remote proxy bindings without forcing users to pick one each time.
This commit is contained in:
1 parent
dfebd9a780
commit
6a875bfced
10 files changed
+240
-24
No files matched your search
@@ -596,13 +596,15 @@ def create_sub2api_service(
|
||||
api_url: str,
|
||||
api_key: str,
|
||||
enabled: bool = True,
|
||||
priority: int = 0
|
||||
priority: int = 0,
|
||||
default_remote_proxy_id: Optional[int] = None,
|
||||
) -> Sub2ApiService:
|
||||
"""创建 Sub2API 服务配置"""
|
||||
svc = Sub2ApiService(
|
||||
name=name,
|
||||
api_url=api_url,
|
||||
api_key=api_key,
|
||||
default_remote_proxy_id=default_remote_proxy_id,
|
||||
enabled=enabled,
|
||||
priority=priority,
|
||||
)
|
||||
|
||||
@@ -152,6 +152,7 @@ class Sub2ApiService(Base):
|
||||
name = Column(String(100), nullable=False) # 服务名称
|
||||
api_url = Column(String(500), nullable=False) # API URL (host)
|
||||
api_key = Column(Text, nullable=False) # x-api-key
|
||||
default_remote_proxy_id = Column(Integer, nullable=True) # 默认远端代理 ID
|
||||
enabled = Column(Boolean, default=True)
|
||||
priority = Column(Integer, default=0) # 优先级
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
|
||||
@@ -111,6 +111,7 @@ class DatabaseSessionManager:
|
||||
("accounts", "subscription_at", "DATETIME"),
|
||||
("accounts", "cookies", "TEXT"),
|
||||
("proxies", "is_default", "BOOLEAN DEFAULT 0"),
|
||||
("sub2api_services", "default_remote_proxy_id", "INTEGER"),
|
||||
]
|
||||
|
||||
# 确保新表存在(create_tables 已处理,此处兜底)
|
||||
|
||||
@@ -819,6 +819,7 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
# 解析指定的 Sub2API 服务
|
||||
api_url = None
|
||||
api_key = None
|
||||
svc = None
|
||||
if request.service_id:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, request.service_id)
|
||||
@@ -830,10 +831,11 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
with get_db() as db:
|
||||
svcs = crud.get_sub2api_services(db, enabled=True)
|
||||
if svcs:
|
||||
api_url = svcs[0].api_url
|
||||
api_key = svcs[0].api_key
|
||||
svc = svcs[0]
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
if not api_url or not api_key:
|
||||
if not api_url or not api_key or not svc:
|
||||
raise HTTPException(status_code=400, detail="未找到可用的 Sub2API 服务,请先在设置中配置")
|
||||
|
||||
with get_db() as db:
|
||||
@@ -842,11 +844,13 @@ async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
|
||||
request.status_filter, request.email_service_filter, request.search_filter
|
||||
)
|
||||
|
||||
selected_proxy_id = request.proxy_id if "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id
|
||||
|
||||
results = batch_upload_to_sub2api(
|
||||
ids, api_url, api_key,
|
||||
concurrency=request.concurrency,
|
||||
priority=request.priority,
|
||||
proxy_id=request.proxy_id,
|
||||
proxy_id=selected_proxy_id,
|
||||
)
|
||||
return results
|
||||
|
||||
@@ -858,10 +862,11 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
service_id = request.service_id if request else None
|
||||
concurrency = request.concurrency if request else 3
|
||||
priority = request.priority if request else 50
|
||||
proxy_id = request.proxy_id if request else None
|
||||
proxy_id = request.proxy_id if request and "proxy_id" in request.model_fields_set else None
|
||||
|
||||
api_url = None
|
||||
api_key = None
|
||||
svc = None
|
||||
if service_id:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, service_id)
|
||||
@@ -873,10 +878,11 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
with get_db() as db:
|
||||
svcs = crud.get_sub2api_services(db, enabled=True)
|
||||
if svcs:
|
||||
api_url = svcs[0].api_url
|
||||
api_key = svcs[0].api_key
|
||||
svc = svcs[0]
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
if not api_url or not api_key:
|
||||
if not api_url or not api_key or not svc:
|
||||
raise HTTPException(status_code=400, detail="未找到可用的 Sub2API 服务,请先在设置中配置")
|
||||
|
||||
with get_db() as db:
|
||||
@@ -888,7 +894,9 @@ async def upload_account_to_sub2api(account_id: int, request: Optional[Sub2ApiUp
|
||||
|
||||
success, message = upload_to_sub2api(
|
||||
[account], api_url, api_key,
|
||||
concurrency=concurrency, priority=priority, proxy_id=proxy_id
|
||||
concurrency=concurrency,
|
||||
priority=priority,
|
||||
proxy_id=proxy_id if request and "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id,
|
||||
)
|
||||
if success:
|
||||
return {"success": True, "message": message}
|
||||
|
||||
@@ -462,7 +462,12 @@ def _run_sync_registration_task(task_uuid: str, email_service_type: str, proxy:
|
||||
if not _svc:
|
||||
continue
|
||||
log_callback(f"[Sub2API] 正在把账号发往服务站: {_svc.name}")
|
||||
_ok, _msg = upload_to_sub2api([saved_account], _svc.api_url, _svc.api_key)
|
||||
_ok, _msg = upload_to_sub2api(
|
||||
[saved_account],
|
||||
_svc.api_url,
|
||||
_svc.api_key,
|
||||
proxy_id=_svc.default_remote_proxy_id,
|
||||
)
|
||||
log_callback(f"[Sub2API] {'成功' if _ok else '失败'}({_svc.name}): {_msg}")
|
||||
except Exception as _e:
|
||||
log_callback(f"[Sub2API] 异常({_sid}): {_e}")
|
||||
|
||||
@@ -23,6 +23,7 @@ class Sub2ApiServiceCreate(BaseModel):
|
||||
name: str
|
||||
api_url: str
|
||||
api_key: str
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: bool = True
|
||||
priority: int = 0
|
||||
|
||||
@@ -31,6 +32,7 @@ class Sub2ApiServiceUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
api_url: Optional[str] = None
|
||||
api_key: Optional[str] = None
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: Optional[bool] = None
|
||||
priority: Optional[int] = None
|
||||
|
||||
@@ -40,6 +42,7 @@ class Sub2ApiServiceResponse(BaseModel):
|
||||
name: str
|
||||
api_url: str
|
||||
has_key: bool
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
enabled: bool
|
||||
priority: int
|
||||
created_at: Optional[str] = None
|
||||
@@ -50,8 +53,10 @@ class Sub2ApiServiceResponse(BaseModel):
|
||||
|
||||
|
||||
class Sub2ApiTestRequest(BaseModel):
|
||||
service_id: Optional[int] = None
|
||||
api_url: Optional[str] = None
|
||||
api_key: Optional[str] = None
|
||||
default_remote_proxy_id: Optional[int] = None
|
||||
|
||||
|
||||
class Sub2ApiUploadRequest(BaseModel):
|
||||
@@ -83,6 +88,7 @@ def _to_response(svc) -> Sub2ApiServiceResponse:
|
||||
name=svc.name,
|
||||
api_url=svc.api_url,
|
||||
has_key=bool(svc.api_key),
|
||||
default_remote_proxy_id=svc.default_remote_proxy_id,
|
||||
enabled=svc.enabled,
|
||||
priority=svc.priority,
|
||||
created_at=svc.created_at.isoformat() if svc.created_at else None,
|
||||
@@ -119,6 +125,23 @@ def _to_remote_proxy_response(proxy: dict) -> Sub2ApiRemoteProxyResponse:
|
||||
)
|
||||
|
||||
|
||||
def _resolve_temp_sub2api_request(request: Sub2ApiTestRequest):
|
||||
svc = None
|
||||
if request.service_id is not None:
|
||||
with get_db() as db:
|
||||
svc = crud.get_sub2api_service_by_id(db, request.service_id)
|
||||
if not svc:
|
||||
raise HTTPException(status_code=404, detail="Sub2API 服务不存在")
|
||||
|
||||
api_url = (request.api_url or (svc.api_url if svc else "")).strip()
|
||||
api_key = (request.api_key or (svc.api_key if svc else "")).strip()
|
||||
|
||||
if not api_url or not api_key:
|
||||
raise HTTPException(status_code=400, detail="api_url 和 api_key 不能为空")
|
||||
|
||||
return svc, api_url, api_key
|
||||
|
||||
|
||||
# ============== API Endpoints ==============
|
||||
|
||||
@router.get("", response_model=List[Sub2ApiServiceResponse])
|
||||
@@ -140,6 +163,7 @@ async def create_sub2api_service(request: Sub2ApiServiceCreate):
|
||||
api_key=request.api_key,
|
||||
enabled=request.enabled,
|
||||
priority=request.priority,
|
||||
default_remote_proxy_id=request.default_remote_proxy_id,
|
||||
)
|
||||
return _to_response(svc)
|
||||
|
||||
@@ -161,6 +185,33 @@ async def list_remote_sub2api_proxies(service_id: Optional[int] = None):
|
||||
)
|
||||
|
||||
|
||||
@router.post("/remote-proxies", response_model=Sub2ApiRemoteProxyListResponse)
|
||||
async def list_remote_sub2api_proxies_direct(request: Sub2ApiTestRequest):
|
||||
"""按临时 Sub2API 配置拉取远端代理列表(用于新增前选择默认代理)"""
|
||||
svc, api_url, api_key = _resolve_temp_sub2api_request(request)
|
||||
|
||||
try:
|
||||
proxies = fetch_remote_sub2api_proxies(api_url, api_key)
|
||||
proxy_items = [_to_remote_proxy_response(proxy) for proxy in proxies]
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||
|
||||
return Sub2ApiRemoteProxyListResponse(
|
||||
service=_to_response(svc) if svc else Sub2ApiServiceResponse(
|
||||
id=0,
|
||||
name="未保存服务",
|
||||
api_url=api_url,
|
||||
has_key=bool(api_key),
|
||||
default_remote_proxy_id=request.default_remote_proxy_id,
|
||||
enabled=True,
|
||||
priority=0,
|
||||
created_at=None,
|
||||
updated_at=None,
|
||||
),
|
||||
proxies=proxy_items,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{service_id}", response_model=Sub2ApiServiceResponse)
|
||||
async def get_sub2api_service(service_id: int):
|
||||
"""获取单个 Sub2API 服务详情"""
|
||||
@@ -183,6 +234,7 @@ async def get_sub2api_service_full(service_id: int):
|
||||
"name": svc.name,
|
||||
"api_url": svc.api_url,
|
||||
"api_key": svc.api_key,
|
||||
"default_remote_proxy_id": svc.default_remote_proxy_id,
|
||||
"enabled": svc.enabled,
|
||||
"priority": svc.priority,
|
||||
}
|
||||
@@ -204,6 +256,8 @@ async def update_sub2api_service(service_id: int, request: Sub2ApiServiceUpdate)
|
||||
# api_key 留空则保持原值
|
||||
if request.api_key:
|
||||
update_data["api_key"] = request.api_key
|
||||
if "default_remote_proxy_id" in request.model_fields_set:
|
||||
update_data["default_remote_proxy_id"] = request.default_remote_proxy_id
|
||||
if request.enabled is not None:
|
||||
update_data["enabled"] = request.enabled
|
||||
if request.priority is not None:
|
||||
@@ -238,9 +292,8 @@ async def test_sub2api_service(service_id: int):
|
||||
@router.post("/test-connection")
|
||||
async def test_sub2api_connection_direct(request: Sub2ApiTestRequest):
|
||||
"""直接测试 Sub2API 连接(用于添加前验证)"""
|
||||
if not request.api_url or not request.api_key:
|
||||
raise HTTPException(status_code=400, detail="api_url 和 api_key 不能为空")
|
||||
success, message = test_sub2api_connection(request.api_url, request.api_key)
|
||||
_svc, api_url, api_key = _resolve_temp_sub2api_request(request)
|
||||
success, message = test_sub2api_connection(api_url, api_key)
|
||||
return {"success": success, "message": message}
|
||||
|
||||
|
||||
@@ -263,12 +316,14 @@ async def upload_accounts_to_sub2api(request: Sub2ApiUploadRequest):
|
||||
api_url = svc.api_url
|
||||
api_key = svc.api_key
|
||||
|
||||
selected_proxy_id = request.proxy_id if "proxy_id" in request.model_fields_set else svc.default_remote_proxy_id
|
||||
|
||||
results = batch_upload_to_sub2api(
|
||||
request.account_ids,
|
||||
api_url,
|
||||
api_key,
|
||||
concurrency=request.concurrency,
|
||||
priority=request.priority,
|
||||
proxy_id=request.proxy_id,
|
||||
proxy_id=selected_proxy_id,
|
||||
)
|
||||
return results
|
||||
Reference in new issue
Block a user