refactor: 平台改为代码内置 provider 架构,一次性迁移现有数据 - 新增 app/providers:BalanceProvider 基类 + DeepSeek 适配器 + 注册表 - platforms 表去除 method/url/headers/body/balance_path,新增 provider_id - 现有数据库已一次性迁移(备份 data/monitor.db.bak-v1),不保留迁移工具 - 平台 UI 改为选择内置提供方;fetcher/monitor 走 provider 构建请求与解析 - 表达式引擎(运算符/函数)随架构保留,供 provider 内部使用 - 测试更新至 provider 模式,共 92 个
This commit is contained in:
+32
-28
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import secrets
|
||||
import sqlite3
|
||||
@@ -27,6 +26,7 @@ from app.models import (
|
||||
SettingsUpdate,
|
||||
)
|
||||
from app.monitor import Monitor
|
||||
from app.providers import get_provider, list_providers as list_providers_svc
|
||||
|
||||
logger = logging.getLogger("monitor.api")
|
||||
|
||||
@@ -130,36 +130,40 @@ def create_app(cfg: Config | None = None) -> FastAPI:
|
||||
|
||||
# ---------- 平台 ----------
|
||||
|
||||
@app.get("/api/providers", dependencies=[Depends(require_auth)])
|
||||
def list_providers():
|
||||
"""代码内置的平台适配器列表(新增平台 = 代码扩展)。"""
|
||||
return list_providers_svc()
|
||||
|
||||
@app.get("/api/platforms", dependencies=[Depends(require_auth)])
|
||||
def list_platforms():
|
||||
with db.get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"""SELECT p.*, (SELECT COUNT(*) FROM accounts a WHERE a.platform_id = p.id) AS account_count
|
||||
"""SELECT p.id, p.name, p.currency, p.icon, p.provider_id,
|
||||
p.interval_seconds, p.retry_count, p.timeout_seconds,
|
||||
p.enabled, p.note, p.created_at, p.updated_at,
|
||||
(SELECT COUNT(*) FROM accounts a WHERE a.platform_id = p.id) AS account_count
|
||||
FROM platforms p ORDER BY p.id"""
|
||||
).fetchall()
|
||||
result = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
try:
|
||||
d["headers"] = json.loads(d["headers"]) if d["headers"] else {}
|
||||
except (ValueError, TypeError):
|
||||
d["headers"] = {}
|
||||
result.append(d)
|
||||
return result
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
@app.post("/api/platforms", dependencies=[Depends(require_auth)])
|
||||
def create_platform(body: PlatformCreate):
|
||||
provider = get_provider(body.provider_id)
|
||||
if provider is None:
|
||||
raise HTTPException(status_code=400, detail=f"不支持的平台提供方: {body.provider_id}")
|
||||
currency = body.currency or provider.currency
|
||||
icon = body.icon or provider.icon
|
||||
try:
|
||||
with db.get_conn() as conn:
|
||||
cur = conn.execute(
|
||||
"""INSERT INTO platforms (name, currency, icon, method, url, headers, body,
|
||||
balance_path, interval_seconds, retry_count, timeout_seconds, enabled, note)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
"""INSERT INTO platforms (provider_id, name, currency, icon,
|
||||
interval_seconds, retry_count, timeout_seconds, enabled, note)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||
(
|
||||
body.name, body.currency, body.icon, body.method, body.url,
|
||||
__import__("json").dumps(body.headers, ensure_ascii=False),
|
||||
body.body, body.balance_path, body.interval_seconds,
|
||||
body.retry_count, body.timeout_seconds, int(body.enabled), body.note,
|
||||
body.provider_id, body.name, currency, icon,
|
||||
body.interval_seconds, body.retry_count, body.timeout_seconds,
|
||||
int(body.enabled), body.note,
|
||||
),
|
||||
)
|
||||
pid = cur.lastrowid
|
||||
@@ -172,22 +176,22 @@ def create_app(cfg: Config | None = None) -> FastAPI:
|
||||
@app.put("/api/platforms/{pid}", dependencies=[Depends(require_auth)])
|
||||
def update_platform(pid: int, body: PlatformUpdate):
|
||||
fields = {}
|
||||
if body.provider_id is not None:
|
||||
provider = get_provider(body.provider_id)
|
||||
if provider is None:
|
||||
raise HTTPException(status_code=400, detail=f"不支持的平台提供方: {body.provider_id}")
|
||||
fields["provider_id"] = body.provider_id
|
||||
# 换 provider 时若未显式给货币/图标,则重置为 provider 默认
|
||||
if "currency" not in body.model_fields_set:
|
||||
fields["currency"] = provider.currency
|
||||
if "icon" not in body.model_fields_set:
|
||||
fields["icon"] = provider.icon
|
||||
if body.name is not None:
|
||||
fields["name"] = body.name
|
||||
if body.currency is not None:
|
||||
fields["currency"] = body.currency
|
||||
if body.icon is not None:
|
||||
fields["icon"] = body.icon
|
||||
if body.method is not None:
|
||||
fields["method"] = body.method
|
||||
if body.url is not None:
|
||||
fields["url"] = body.url
|
||||
if body.headers is not None:
|
||||
fields["headers"] = __import__("json").dumps(body.headers, ensure_ascii=False)
|
||||
if body.body is not None:
|
||||
fields["body"] = body.body
|
||||
if body.balance_path is not None:
|
||||
fields["balance_path"] = body.balance_path
|
||||
if body.interval_seconds is not None:
|
||||
fields["interval_seconds"] = body.interval_seconds
|
||||
if body.retry_count is not None:
|
||||
|
||||
Reference in New Issue
Block a user